library(swimplot) library(coxphf) library(grid) library(gtable) library(readr) library(mosaic) library(dplyr) library(officer) library(flextable) library(survival) library(survminer) library(gridtext) library(ggplot2) library(scales) library(ggthemes) library(tidyverse) library(gtsummary) library(flextable) library(parameters) library(car) library(grid) library(ComplexHeatmap) library(readxl) library(janitor) library(rms) library(DT)

#Demographics Table

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

circ_data_subset <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    LVI,
    PNI,
    Grade,
    Location,
    Surg.Type,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    LVI = factor(LVI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    PNI = factor(PNI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    Grade = factor(Grade, levels = c("G1", "G2/G3")),
    Location = factor(Location, levels = c("Upper rectum (Ra)", "Lower rectum (Rb)")),
    Surg.Type = factor(Surg.Type),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months))
table1 <- circ_data_subset %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
table1
Characteristic N = 2501
Age 67 (38 - 92)
Gender
    Male 162 (65%)
    Female 88 (35%)
ECOG
    0 228 (91%)
    1 22 (8.8%)
pT
    T1-T2 29 (12%)
    T3-T4 221 (88%)
pN
    N0 99 (40%)
    N1-N2 151 (60%)
LVI 220 (88%)
PNI 109 (44%)
Grade
    G1 144 (58%)
    G2/G3 106 (42%)
Location
    Upper rectum (Ra) 127 (51%)
    Lower rectum (Rb) 123 (49%)
Surg.Type
    APR 35 (14%)
    HAR 8 (3.2%)
    Hartmann procedure 2 (0.8%)
    ISR 11 (4.4%)
    LAR 189 (76%)
    Other 4 (1.6%)
    TPE 1 (0.4%)
Stage
    II 100 (40%)
    III 150 (60%)
ACT
    Adjuvant Chemotherapy 123 (49%)
    Observation 127 (51%)
BRAF.V600E
    BRAF wt 248 (99%)
    BRAF V600E 2 (0.8%)
RAS
    RAS wt 122 (49%)
    RAS mut 128 (51%)
MSI
    MSS 247 (99%)
    MSI-High 3 (1.2%)
RFS.Event
    Recurrence 48 (19%)
    No Recurrence 202 (81%)
OS.Event
    Deceased 11 (4.4%)
    Alive 239 (96%)
OS.months 22.0 (1.2 - 35.9)
1 Median (Min - Max); n (%)
fit1 <- as_flex_table(
  table1,
  include = everything(),
  return_calls = FALSE)
fit1

Characteristic

N = 2501

Age

67 (38 - 92)

Gender

Male

162 (65%)

Female

88 (35%)

ECOG

0

228 (91%)

1

22 (8.8%)

pT

T1-T2

29 (12%)

T3-T4

221 (88%)

pN

N0

99 (40%)

N1-N2

151 (60%)

LVI

220 (88%)

PNI

109 (44%)

Grade

G1

144 (58%)

G2/G3

106 (42%)

Location

Upper rectum (Ra)

127 (51%)

Lower rectum (Rb)

123 (49%)

Surg.Type

APR

35 (14%)

HAR

8 (3.2%)

Hartmann procedure

2 (0.8%)

ISR

11 (4.4%)

LAR

189 (76%)

Other

4 (1.6%)

TPE

1 (0.4%)

Stage

II

100 (40%)

III

150 (60%)

ACT

Adjuvant Chemotherapy

123 (49%)

Observation

127 (51%)

BRAF.V600E

BRAF wt

248 (99%)

BRAF V600E

2 (0.8%)

RAS

RAS wt

122 (49%)

RAS mut

128 (51%)

MSI

MSS

247 (99%)

MSI-High

3 (1.2%)

RFS.Event

Recurrence

48 (19%)

No Recurrence

202 (81%)

OS.Event

Deceased

11 (4.4%)

Alive

239 (96%)

OS.months

22.0 (1.2 - 35.9)

1Median (Min - Max); n (%)

save_as_docx(fit1, path= "~/Downloads/table1.docx")

#Demographics Table by MRD ctDNA Status

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data_subset1 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    LVI,
    PNI,
    Grade,
    Location,
    Surg.Type,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    LVI = factor(LVI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    PNI = factor(PNI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    Grade = factor(Grade, levels = c("G1", "G2/G3")),
    Location = factor(Location, levels = c("Upper rectum (Ra)", "Lower rectum (Rb)")),
    Surg.Type = factor(Surg.Type),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months))

circ_data1 <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data_subset2 <- circ_data %>%
  select(
    Age,
    Gender,
    ECOG,
    pT,
    pN,
    LVI,
    PNI,
    Grade,
    Location,
    Surg.Type,
    Stage,
    ACT,
    BRAF.V600E,
    RAS,
    MSI,
    RFS.Event,
    OS.Event,
    OS.months,
    ctDNA.MRD) %>%
  mutate(
    Age = as.numeric(Age),
    Gender = factor(Gender, levels = c("Male", "Female")),
    ECOG = factor(ECOG, levels = c(0, 1)),
    pT = factor(pT, levels = c("T1-T2", "T3-T4")),
    pN = factor(pN, levels = c("N0", "N1-N2")),
    LVI = factor(LVI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    PNI = factor(PNI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No")),
    Grade = factor(Grade, levels = c("G1", "G2/G3")),
    Location = factor(Location, levels = c("Upper rectum (Ra)", "Lower rectum (Rb)")),
    Surg.Type = factor(Surg.Type),
    Stage = factor(Stage, levels = c("II", "III")),
    ACT = factor(ACT, levels = c("TRUE", "FALSE"), labels = c("Adjuvant Chemotherapy", "Observation")),
    BRAF.V600E = factor(BRAF.V600E, levels = c("WT", "MUT"), labels = c("BRAF wt", "BRAF V600E")),
    RAS = factor(RAS, levels = c("WT", "MUT"), labels = c("RAS wt", "RAS mut")),
    MSI = factor(MSI, levels = c("MSS", "MSI-High")),
    RFS.Event = factor(RFS.Event, levels = c("TRUE", "FALSE"), labels = c("Recurrence", "No Recurrence")),
    OS.Event = factor(OS.Event, levels = c("TRUE", "FALSE"), labels = c("Deceased", "Alive")),
    OS.months = as.numeric(OS.months),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 2471
Age 67 (38 - 92)
Gender
    Male 162 (66%)
    Female 85 (34%)
ECOG
    0 225 (91%)
    1 22 (8.9%)
pT
    T1-T2 29 (12%)
    T3-T4 218 (88%)
pN
    N0 98 (40%)
    N1-N2 149 (60%)
LVI 218 (88%)
PNI 107 (43%)
Grade
    G1 142 (57%)
    G2/G3 105 (43%)
Location
    Upper rectum (Ra) 126 (51%)
    Lower rectum (Rb) 121 (49%)
Surg.Type
    APR 35 (14%)
    HAR 8 (3.2%)
    Hartmann procedure 2 (0.8%)
    ISR 11 (4.5%)
    LAR 186 (75%)
    Other 4 (1.6%)
    TPE 1 (0.4%)
Stage
    II 99 (40%)
    III 148 (60%)
ACT
    Adjuvant Chemotherapy 121 (49%)
    Observation 126 (51%)
BRAF.V600E
    BRAF wt 245 (99%)
    BRAF V600E 2 (0.8%)
RAS
    RAS wt 121 (49%)
    RAS mut 126 (51%)
MSI
    MSS 244 (99%)
    MSI-High 3 (1.2%)
RFS.Event
    Recurrence 48 (19%)
    No Recurrence 199 (81%)
OS.Event
    Deceased 11 (4.5%)
    Alive 236 (96%)
OS.months 22.0 (1.2 - 35.9)
1 Median (Min - Max); n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # add this line to subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p() %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE
N = 212
1
POSITIVE
N = 35
1
p-value2
Age 67 (38 - 92) 67 (43 - 82) 0.6
Gender

0.5
    Male 141 (67%) 21 (60%)
    Female 71 (33%) 14 (40%)
ECOG

0.3
    0 191 (90%) 34 (97%)
    1 21 (9.9%) 1 (2.9%)
pT

0.8
    T1-T2 26 (12%) 3 (8.6%)
    T3-T4 186 (88%) 32 (91%)
pN

<0.001
    N0 95 (45%) 3 (8.6%)
    N1-N2 117 (55%) 32 (91%)
LVI 184 (87%) 34 (97%) 0.092
PNI 86 (41%) 21 (60%) 0.032
Grade

0.7
    G1 123 (58%) 19 (54%)
    G2/G3 89 (42%) 16 (46%)
Location

0.5
    Upper rectum (Ra) 110 (52%) 16 (46%)
    Lower rectum (Rb) 102 (48%) 19 (54%)
Surg.Type

0.5
    APR 27 (13%) 8 (23%)
    HAR 7 (3.3%) 1 (2.9%)
    Hartmann procedure 2 (0.9%) 0 (0%)
    ISR 11 (5.2%) 0 (0%)
    LAR 161 (76%) 25 (71%)
    Other 3 (1.4%) 1 (2.9%)
    TPE 1 (0.5%) 0 (0%)
Stage

<0.001
    II 96 (45%) 3 (8.6%)
    III 116 (55%) 32 (91%)
ACT

0.004
    Adjuvant Chemotherapy 96 (45%) 25 (71%)
    Observation 116 (55%) 10 (29%)
BRAF.V600E

>0.9
    BRAF wt 210 (99%) 35 (100%)
    BRAF V600E 2 (0.9%) 0 (0%)
RAS

0.060
    RAS wt 109 (51%) 12 (34%)
    RAS mut 103 (49%) 23 (66%)
MSI

>0.9
    MSS 209 (99%) 35 (100%)
    MSI-High 3 (1.4%) 0 (0%)
RFS.Event

<0.001
    Recurrence 23 (11%) 25 (71%)
    No Recurrence 189 (89%) 10 (29%)
OS.Event

0.2
    Deceased 8 (3.8%) 3 (8.6%)
    Alive 204 (96%) 32 (91%)
OS.months 22.0 (7.5 - 35.9) 16.4 (1.2 - 34.9) 0.082
1 Median (Min - Max); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test; Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic
Table 1
Table 2
N = 2471 NEGATIVE
N = 212
1
POSITIVE
N = 35
1
p-value2
Age 67 (38 - 92) 67 (38 - 92) 67 (43 - 82) 0.6
Gender


0.5
    Male 162 (66%) 141 (67%) 21 (60%)
    Female 85 (34%) 71 (33%) 14 (40%)
ECOG


0.3
    0 225 (91%) 191 (90%) 34 (97%)
    1 22 (8.9%) 21 (9.9%) 1 (2.9%)
pT


0.8
    T1-T2 29 (12%) 26 (12%) 3 (8.6%)
    T3-T4 218 (88%) 186 (88%) 32 (91%)
pN


<0.001
    N0 98 (40%) 95 (45%) 3 (8.6%)
    N1-N2 149 (60%) 117 (55%) 32 (91%)
LVI 218 (88%) 184 (87%) 34 (97%) 0.092
PNI 107 (43%) 86 (41%) 21 (60%) 0.032
Grade


0.7
    G1 142 (57%) 123 (58%) 19 (54%)
    G2/G3 105 (43%) 89 (42%) 16 (46%)
Location


0.5
    Upper rectum (Ra) 126 (51%) 110 (52%) 16 (46%)
    Lower rectum (Rb) 121 (49%) 102 (48%) 19 (54%)
Surg.Type


0.5
    APR 35 (14%) 27 (13%) 8 (23%)
    HAR 8 (3.2%) 7 (3.3%) 1 (2.9%)
    Hartmann procedure 2 (0.8%) 2 (0.9%) 0 (0%)
    ISR 11 (4.5%) 11 (5.2%) 0 (0%)
    LAR 186 (75%) 161 (76%) 25 (71%)
    Other 4 (1.6%) 3 (1.4%) 1 (2.9%)
    TPE 1 (0.4%) 1 (0.5%) 0 (0%)
Stage


<0.001
    II 99 (40%) 96 (45%) 3 (8.6%)
    III 148 (60%) 116 (55%) 32 (91%)
ACT


0.004
    Adjuvant Chemotherapy 121 (49%) 96 (45%) 25 (71%)
    Observation 126 (51%) 116 (55%) 10 (29%)
BRAF.V600E


>0.9
    BRAF wt 245 (99%) 210 (99%) 35 (100%)
    BRAF V600E 2 (0.8%) 2 (0.9%) 0 (0%)
RAS


0.060
    RAS wt 121 (49%) 109 (51%) 12 (34%)
    RAS mut 126 (51%) 103 (49%) 23 (66%)
MSI


>0.9
    MSS 244 (99%) 209 (99%) 35 (100%)
    MSI-High 3 (1.2%) 3 (1.4%) 0 (0%)
RFS.Event


<0.001
    Recurrence 48 (19%) 23 (11%) 25 (71%)
    No Recurrence 199 (81%) 189 (89%) 10 (29%)
OS.Event


0.2
    Deceased 11 (4.5%) 8 (3.8%) 3 (8.6%)
    Alive 236 (96%) 204 (96%) 32 (91%)
OS.months 22.0 (1.2 - 35.9) 22.0 (7.5 - 35.9) 16.4 (1.2 - 34.9) 0.082
1 Median (Min - Max); n (%)
2 Wilcoxon rank sum test; Pearson’s Chi-squared test; Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE)
fit1

Table 1

Table 2

Characteristic

N = 2471

NEGATIVE
N = 2121

POSITIVE
N = 351

p-value2

Age

67 (38 - 92)

67 (38 - 92)

67 (43 - 82)

0.6

Gender

0.5

Male

162 (66%)

141 (67%)

21 (60%)

Female

85 (34%)

71 (33%)

14 (40%)

ECOG

0.3

0

225 (91%)

191 (90%)

34 (97%)

1

22 (8.9%)

21 (9.9%)

1 (2.9%)

pT

0.8

T1-T2

29 (12%)

26 (12%)

3 (8.6%)

T3-T4

218 (88%)

186 (88%)

32 (91%)

pN

<0.001

N0

98 (40%)

95 (45%)

3 (8.6%)

N1-N2

149 (60%)

117 (55%)

32 (91%)

LVI

218 (88%)

184 (87%)

34 (97%)

0.092

PNI

107 (43%)

86 (41%)

21 (60%)

0.032

Grade

0.7

G1

142 (57%)

123 (58%)

19 (54%)

G2/G3

105 (43%)

89 (42%)

16 (46%)

Location

0.5

Upper rectum (Ra)

126 (51%)

110 (52%)

16 (46%)

Lower rectum (Rb)

121 (49%)

102 (48%)

19 (54%)

Surg.Type

0.5

APR

35 (14%)

27 (13%)

8 (23%)

HAR

8 (3.2%)

7 (3.3%)

1 (2.9%)

Hartmann procedure

2 (0.8%)

2 (0.9%)

0 (0%)

ISR

11 (4.5%)

11 (5.2%)

0 (0%)

LAR

186 (75%)

161 (76%)

25 (71%)

Other

4 (1.6%)

3 (1.4%)

1 (2.9%)

TPE

1 (0.4%)

1 (0.5%)

0 (0%)

Stage

<0.001

II

99 (40%)

96 (45%)

3 (8.6%)

III

148 (60%)

116 (55%)

32 (91%)

ACT

0.004

Adjuvant Chemotherapy

121 (49%)

96 (45%)

25 (71%)

Observation

126 (51%)

116 (55%)

10 (29%)

BRAF.V600E

>0.9

BRAF wt

245 (99%)

210 (99%)

35 (100%)

BRAF V600E

2 (0.8%)

2 (0.9%)

0 (0%)

RAS

0.060

RAS wt

121 (49%)

109 (51%)

12 (34%)

RAS mut

126 (51%)

103 (49%)

23 (66%)

MSI

>0.9

MSS

244 (99%)

209 (99%)

35 (100%)

MSI-High

3 (1.2%)

3 (1.4%)

0 (0%)

RFS.Event

<0.001

Recurrence

48 (19%)

23 (11%)

25 (71%)

No Recurrence

199 (81%)

189 (89%)

10 (29%)

OS.Event

0.2

Deceased

11 (4.5%)

8 (3.8%)

3 (8.6%)

Alive

236 (96%)

204 (96%)

32 (91%)

OS.months

22.0 (1.2 - 35.9)

22.0 (7.5 - 35.9)

16.4 (1.2 - 34.9)

0.082

1Median (Min - Max); n (%)

2Wilcoxon rank sum test; Pearson's Chi-squared test; Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#DFS in Complete Cohort (N=250)

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~CohortB, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    CohortB, data = circ_data)

       n events median 0.95LCL 0.95UCL
[1,] 250     53     NA      NA      NA
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ CohortB, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue"), title="DFS - Complete Cohort (n=250)", ylab= "Progression-Free Survival", xlab="Months from Surgery", legend.labs=c("Complete cohort"), legend.title="")

summary(KM_curve, times= c(12, 24, 36))
Call: survfit(formula = surv_object ~ CohortB, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    163      42    0.826  0.0245        0.772        0.868
   24     37      10    0.766  0.0294        0.702        0.818

#OS in Complete Cohort (N=250)

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

survfit(Surv(time = circ_data$OS.months, event = circ_data$OS.Event)~CohortB, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$OS.months, event = circ_data$OS.Event) ~ 
    CohortB, data = circ_data)

       n events median 0.95LCL 0.95UCL
[1,] 250     11     NA      NA      NA
surv_object <-Surv(time = circ_data$OS.months, event = circ_data$OS.Event)
KM_curve <- survfit(surv_object ~ CohortB, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue"), title="OS - Complete Cohort (n=250)", ylab= "Overall Survival", xlab="Months from Surgery", legend.labs=c("Complete cohort"), legend.title="")

summary(KM_curve, times= c(12, 24, 36))
Call: survfit(formula = surv_object ~ CohortB, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    195       3    0.988 0.00691        0.963        0.996
   24     55       7    0.934 0.02271        0.872        0.966

#ctDNA Detection Rates by Window and Stages

#ctDNA at Baseline
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Baseline <- factor(circ_data$ctDNA.Baseline, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Baseline %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Baseline, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Baseline == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at MRD Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.MRD == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.MRD, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.MRD == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA at Surveillance Window
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
circ_data <- subset(circ_data, ctDNA.Surveillance %in% c("NEGATIVE", "POSITIVE"))
circ_data$Stage <- factor(circ_data$Stage, levels=c("II", "III"))
positive_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance == "POSITIVE", by=list(circ_data$Stage), FUN=sum)
total_counts_by_stage <- aggregate(circ_data$ctDNA.Surveillance, by=list(circ_data$Stage), FUN=length)
combined_data <- data.frame(
  Stage = total_counts_by_stage$Group.1,
  Total_Count = total_counts_by_stage$x,
  Positive_Count = positive_counts_by_stage$x,
  Rate = (positive_counts_by_stage$x / total_counts_by_stage$x) * 100  # Convert to percentage
)
combined_data$Rate <- sprintf("%.2f%%", combined_data$Rate)
overall_total_count <- nrow(circ_data)
overall_positive_count <- nrow(circ_data[circ_data$ctDNA.Surveillance == "POSITIVE",])
overall_positivity_rate <- (overall_positive_count / overall_total_count) * 100  # Convert to percentage
overall_row <- data.frame(
  Stage = "Overall",
  Total_Count = overall_total_count,
  Positive_Count = overall_positive_count,
  Rate = sprintf("%.2f%%", overall_positivity_rate)
)
combined_data <- rbind(combined_data, overall_row)
print(combined_data)

#ctDNA MRD Detection rate Stage II vs III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"))
circ_data$Stage_Grouped <- factor(ifelse(circ_data$Stage %in% c("II", "II"), "II", "III"))
contingency_table <- table(circ_data$Stage_Grouped, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
print(contingency_table)
     
      NEGATIVE POSITIVE
  II        96        3
  III      116       32
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 15.364, df = 1, p-value = 8.865e-05

#ctDNA Surveillance Detection rate Stage II vs III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels = c("NEGATIVE", "POSITIVE"))
circ_data$Stage_Grouped <- factor(ifelse(circ_data$Stage %in% c("II", "II"), "II", "III"))
contingency_table <- table(circ_data$Stage_Grouped, circ_data$ctDNA.Surveillance)
chi_square_test <- chisq.test(contingency_table)
print(contingency_table)
     
      NEGATIVE POSITIVE
  II        86        8
  III      107       32
print(chi_square_test)

    Pearson's Chi-squared test with Yates' continuity correction

data:  contingency_table
X-squared = 7.3146, df = 1, p-value = 0.00684

#ctDNA timepoints cadence at the MRD Window

rm(list=ls())
setwd("~/Downloads") 
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]

circ_data$MRD_Time_weeks <- circ_data$ctDNA.MRD.Time / 7

# Plot the histogram
hist(circ_data$MRD_Time_weeks,
     col = 'gray',
     main = 'Surgery to first ctDNA testing at MRD window',
     xlab = 'Weeks from surgery to first ctDNA test at MRD window',
     ylab = 'ctDNA Samples',
     ylim = c(0, 120),
     xlim = c(0, 10),
     breaks = seq(0, 24, 1),
     xaxp = c(0, 24, 24))

#DFS by ctDNA at the MRD Window - All stages Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                     n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 211     28     NA      NA      NA
ctDNA.MRD=POSITIVE  35     25   9.27    7.62    14.1
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 18, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    146      21    0.895  0.0218        0.843        0.930
   18     97       4    0.868  0.0250        0.810        0.910
   24     31       2    0.850  0.0275        0.787        0.896

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   18      5       3    0.219  0.0792       0.0884        0.386
   24      2       0    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 246, number of events= 53 

                    coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 2.2985    9.9592   0.2795 8.222   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     9.959     0.1004     5.758     17.23

Concordance= 0.709  (se = 0.032 )
Likelihood ratio test= 55.38  on 1 df,   p=1e-13
Wald test            = 67.61  on 1 df,   p=<2e-16
Score (logrank) test = 101.2  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 9.96 (5.76-17.23); p = 0"
#Fisher test for DFS percentages at 12, 18, and 24 months
dfs_times <- c(12, 18, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 18 months p-value at 24 months 
        3.289740e-11         6.618049e-13         2.261958e-12 

#Multivariate cox regression at MRD Window for DFS - All stages Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$LVI <- factor(circ_data$LVI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No"))
circ_data$PNI <- factor(circ_data$PNI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No"))
circ_data$Grade <- factor(circ_data$Grade, levels = c("G1", "G2/G3"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.MRD + Gender + Age.Group + ECOG + pT + pN + LVI + PNI + Grade + RAS, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - All Stages", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#DFS by ctDNA at the MRD Window - Stage II Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[!(circ_data$Stage %in% c("III")),]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

                    n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 96      6     NA      NA      NA
ctDNA.MRD=POSITIVE  3      3     13   0.493      NA
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | Stage II", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     73       3    0.967  0.0189        0.900        0.989
   24     13       3    0.923  0.0307        0.835        0.965

                ctDNA.MRD=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     12.0000       2.0000       1.0000       0.6667       0.2722       0.0541       0.9452 
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 99, number of events= 9 

                     coef exp(coef) se(coef)    z Pr(>|z|)    
ctDNA.MRDPOSITIVE  3.3011   27.1423   0.7369 4.48 7.46e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     27.14    0.03684     6.404       115

Concordance= 0.66  (se = 0.077 )
Likelihood ratio test= 12.56  on 1 df,   p=4e-04
Wald test            = 20.07  on 1 df,   p=7e-06
Score (logrank) test = 45.99  on 1 df,   p=1e-11
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 27.14 (6.4-115.04); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        0.1175270483         0.0005355469 

#DFS by ctDNA at the MRD Window - Stage III Landmark MRD timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$Eligible=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[!(circ_data$Stage %in% c("II")),]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.MRD, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.MRD, data = circ_data)

   1 observation deleted due to missingness 
                      n events median 0.95LCL 0.95UCL
ctDNA.MRD=NEGATIVE 1189    203     NA      NA      NA
ctDNA.MRD=POSITIVE  291    233   5.06     4.6    6.51
event_summary <- circ_data %>%
  group_by(ctDNA.MRD) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.MRD, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA MRD window | Stage III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(24, 30))
Call: survfit(formula = surv_object ~ ctDNA.MRD, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

1 observation deleted due to missingness 
                ctDNA.MRD=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24    391     195    0.806  0.0130        0.779        0.830
   30    228       6    0.791  0.0141        0.762        0.817

                ctDNA.MRD=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   24     30     229    0.189  0.0245        0.144        0.239
   30     17       3    0.166  0.0250        0.120        0.218
circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.MRD, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.MRD, data = circ_data)

  n= 1480, number of events= 436 
   (1 observation deleted due to missingness)

                     coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.MRDPOSITIVE 2.24488   9.43924  0.09775 22.97   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                  exp(coef) exp(-coef) lower .95 upper .95
ctDNA.MRDPOSITIVE     9.439     0.1059     7.794     11.43

Concordance= 0.729  (se = 0.011 )
Likelihood ratio test= 467.9  on 1 df,   p=<2e-16
Wald test            = 527.5  on 1 df,   p=<2e-16
Score (logrank) test = 768.2  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 9.44 (7.79-11.43); p = 0"
#Fisher test for DFS percentages at 24 and 30 months
dfs_times <- c(24, 30)
circ_data <- na.omit(circ_data[, c("ctDNA.MRD", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.MRD == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.MRD == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.MRD == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.MRD == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months p-value at 30 months 
        6.506858e-91         5.794183e-92 

#DFS by ACT treatment in MRD negative - Stage II/III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

            n events median 0.95LCL 0.95UCL
ACT=FALSE 115     16     NA      NA      NA
ACT=TRUE   96     12     NA      NA      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Negative ACT vs Observation | Stage II/III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      16.0000      16.0000       0.8419       0.0373       0.7521       0.9013 

                ACT=TRUE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
     24.0000      15.0000      11.0000       0.8612       0.0407       0.7574       0.9228 
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 211, number of events= 28 

            coef exp(coef) se(coef)     z Pr(>|z|)
ACTFALSE 0.06529   1.06747  0.38220 0.171    0.864

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     1.067     0.9368    0.5047     2.258

Concordance= 0.517  (se = 0.048 )
Likelihood ratio test= 0.03  on 1 df,   p=0.9
Wald test            = 0.03  on 1 df,   p=0.9
Score (logrank) test = 0.03  on 1 df,   p=0.9
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.07 (0.5-2.26); p = 0.864"
#Fisher test for DFS percentages at 24
dfs_times <- c(24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ACT == "TRUE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ACT == "FALSE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ACT == "TRUE")
  pos_total <- sum(circ_data$ACT == "FALSE")
  
  neg_surv <- neg_total - sum(circ_data$ACT == "TRUE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ACT == "FALSE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 24 months 
           0.6811626 
#Adjusted HR "ACT vs no ACT" - Non ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ACT <- factor(circ_data$ACT, levels=c("FALSE","TRUE"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", "≥70"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Stage <- factor(circ_data$Stage, levels = c("II", "III"))
circ_data$ECOG <- factor(circ_data$ECOG, levels=c("0","1"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Stage + ECOG, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Stage + 
    ECOG, data = circ_data)

  n= 211, number of events= 28 

                coef exp(coef) se(coef)      z Pr(>|z|)   
ACTTRUE      -0.5269    0.5904   0.4211 -1.251  0.21080   
GenderMale    0.1145    1.1213   0.4081  0.280  0.77910   
Age.Group≥70  0.3280    1.3883   0.4022  0.816  0.41472   
StageIII      1.5211    4.5774   0.4886  3.113  0.00185 **
ECOG1         0.5215    1.6846   0.5509  0.947  0.34383   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

             exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE         0.5904     1.6937    0.2587     1.348
GenderMale      1.1213     0.8918    0.5039     2.495
Age.Group≥70    1.3883     0.7203    0.6311     3.054
StageIII        4.5774     0.2185    1.7569    11.926
ECOG1           1.6846     0.5936    0.5722     4.960

Concordance= 0.71  (se = 0.043 )
Likelihood ratio test= 12.82  on 5 df,   p=0.03
Wald test            = 11.73  on 5 df,   p=0.04
Score (logrank) test = 12.73  on 5 df,   p=0.03

#DFS by ACT treatment in MRD positive - Stage II/III

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ACT, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ACT, data = circ_data)

           n events median 0.95LCL 0.95UCL
ACT=FALSE  6      5   5.62    1.22      NA
ACT=TRUE  25     16   9.33    6.97      NA
event_summary <- circ_data %>%
  group_by(ACT) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ACT, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("red","blue"), title="DFS - ctDNA MRD Positive ACT vs Observation | Stage II/III", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Observation", "ACT"), legend.title="")

summary(KM_curve, times= c(6, 24))
Call: survfit(formula = surv_object ~ ACT, data = circ_data, conf.int = 0.95, 
    conf.type = "log-log")

                ACT=FALSE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
       6.000        2.000        3.000        0.500        0.204        0.111        0.804 

                ACT=TRUE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6     21       4    0.840  0.0733        0.628        0.937
   24      2      12    0.295  0.1026        0.118        0.497
circ_data$ACT <- factor(circ_data$ACT, levels=c("TRUE","FALSE"))
cox_fit <- coxph(surv_object ~ ACT, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT, data = circ_data)

  n= 31, number of events= 21 

           coef exp(coef) se(coef)     z Pr(>|z|)  
ACTFALSE 1.3036    3.6825   0.5572 2.339   0.0193 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

         exp(coef) exp(-coef) lower .95 upper .95
ACTFALSE     3.682     0.2716     1.235     10.98

Concordance= 0.593  (se = 0.045 )
Likelihood ratio test= 4.59  on 1 df,   p=0.03
Wald test            = 5.47  on 1 df,   p=0.02
Score (logrank) test = 6.25  on 1 df,   p=0.01
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 3.68 (1.24-10.98); p = 0.019"
#Adjusted HR "ACT vs no ACT" - Non ACT as reference
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data$DFS.months=circ_data$DFS.months-2
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ACT <- factor(circ_data$ACT, levels=c("FALSE","TRUE"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", "≥70"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Stage <- factor(circ_data$Stage, levels = c("II", "III"))
circ_data$ECOG <- factor(circ_data$ECOG, levels=c("0","1"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ACT + Gender + Age.Group + Stage + ECOG, data=circ_data)
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ACT + Gender + Age.Group + Stage + 
    ECOG, data = circ_data)

  n= 31, number of events= 21 

                 coef exp(coef) se(coef)      z Pr(>|z|)  
ACTTRUE      -1.27835   0.27850  0.59142 -2.162   0.0307 *
GenderMale    0.35495   1.42611  0.51244  0.693   0.4885  
Age.Group≥70  0.12911   1.13782  0.45951  0.281   0.7787  
StageIII      0.08804   1.09203  0.81274  0.108   0.9137  
ECOG1         1.40597   4.07950  1.13540  1.238   0.2156  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

             exp(coef) exp(-coef) lower .95 upper .95
ACTTRUE         0.2785     3.5907   0.08738    0.8876
GenderMale      1.4261     0.7012   0.52236    3.8935
Age.Group≥70    1.1378     0.8789   0.46231    2.8003
StageIII        1.0920     0.9157   0.22204    5.3708
ECOG1           4.0795     0.2451   0.44071   37.7622

Concordance= 0.632  (se = 0.066 )
Likelihood ratio test= 6.01  on 5 df,   p=0.3
Wald test            = 6.81  on 5 df,   p=0.2
Score (logrank) test = 7.76  on 5 df,   p=0.2

#DFS by ctDNA at 3 months - All stages Landmark 3 months timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.3months!="",]
circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)~ctDNA.3months, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.3months, data = circ_data)

                         n events median 0.95LCL 0.95UCL
ctDNA.3months=NEGATIVE 204     31     NA      NA      NA
ctDNA.3months=POSITIVE  19     14   8.28    5.59      NA
event_summary <- circ_data %>%
  group_by(ctDNA.3months) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.3months, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA 3 months | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.3months, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.3months=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    137      26    0.863  0.0252        0.805        0.905
   24     30       4    0.829  0.0293        0.762        0.879

                ctDNA.3months=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      4      14    0.237   0.101       0.0758        0.447
   24      3       0    0.237   0.101       0.0758        0.447
circ_data$ctDNA.3months <- factor(circ_data$ctDNA.3months, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.3months, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.3months, data = circ_data)

  n= 223, number of events= 45 

                        coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.3monthsPOSITIVE 2.0768    7.9792   0.3247 6.397 1.58e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                      exp(coef) exp(-coef) lower .95 upper .95
ctDNA.3monthsPOSITIVE     7.979     0.1253     4.223     15.08

Concordance= 0.641  (se = 0.034 )
Likelihood ratio test= 29.34  on 1 df,   p=6e-08
Wald test            = 40.92  on 1 df,   p=2e-10
Score (logrank) test = 57.62  on 1 df,   p=3e-14
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 7.98 (4.22-15.08); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.3months == "NEGATIVE" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.3months == "POSITIVE" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.3months == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.3months == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.3months == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.3mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.3months == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.3mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        2.546518e-08         1.138180e-07 

#DFS by ctDNA at 6 months - All stages Landmark 6 months timepoint

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.6months!="",]
circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.6months, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.6months, data = circ_data)

                         n events median 0.95LCL 0.95UCL
ctDNA.6months=NEGATIVE 173     21     NA      NA      NA
ctDNA.6months=POSITIVE   9      7   3.68     2.6      NA
event_summary <- circ_data %>%
  group_by(ctDNA.6months) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.6months, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA 6 months | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(6, 24))
Call: survfit(formula = surv_object ~ ctDNA.6months, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.6months=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
    6    134      14    0.915  0.0217        0.861        0.949
   24     14       7    0.832  0.0420        0.730        0.898

                ctDNA.6months=POSITIVE 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      6.0000       2.0000       6.0000       0.3333       0.1571       0.0783       0.6226 
circ_data$ctDNA.6months <- factor(circ_data$ctDNA.6months, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.6months, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.6months, data = circ_data)

  n= 182, number of events= 28 

                         coef exp(coef) se(coef)    z Pr(>|z|)    
ctDNA.6monthsPOSITIVE  2.7187   15.1598   0.4577 5.94 2.85e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                      exp(coef) exp(-coef) lower .95 upper .95
ctDNA.6monthsPOSITIVE     15.16    0.06596     6.182     37.18

Concordance= 0.628  (se = 0.042 )
Likelihood ratio test= 22.48  on 1 df,   p=2e-06
Wald test            = 35.29  on 1 df,   p=3e-09
Score (logrank) test = 62.3  on 1 df,   p=3e-15
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 15.16 (6.18-37.18); p = 0"
#Fisher test for DFS percentages at 6 and 24 months
dfs_times <- c(6, 24)
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.6months == "NEGATIVE" & circ_data$DFS.6mo.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.6months == "POSITIVE" & circ_data$DFS.6mo.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.6months == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.6months == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.6months == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.6mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.6months == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.6mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
 p-value at 6 months p-value at 24 months 
        5.667547e-05         2.922826e-05 

#DFS by ctDNA Clearance ACT-treated at 3 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",] 
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.3months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.3mo.months>=0,]
survfit(Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   97 observations deleted due to missingness 
                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 16      8  14.16    6.01      NA
ctDNA.Dynamics=2  8      7   8.05    5.59      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.3mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 3 months ACT-treated | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

97 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      5       7    0.516   0.139        0.229        0.742
   24      2       1    0.413   0.145        0.146        0.665

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
    12.00000      1.00000      7.00000      0.12500      0.11693      0.00659      0.42271 
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 24, number of events= 15 
   (97 observations deleted due to missingness)

                             coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsNo Clearance 0.8707    2.3885   0.5227 1.666   0.0958 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     2.389     0.4187    0.8574     6.654

Concordance= 0.605  (se = 0.066 )
Likelihood ratio test= 2.65  on 1 df,   p=0.1
Wald test            = 2.77  on 1 df,   p=0.1
Score (logrank) test = 2.95  on 1 df,   p=0.09
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 2.39 (0.86-6.65); p = 0.096"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.3mo.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "Clearance" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == FALSE)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "No Clearance" & circ_data$DFS.3mo.months >= time & circ_data$DFS.Event == FALSE)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "Clearance")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "No Clearance")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "Clearance" & circ_data$DFS.Event == TRUE & circ_data$DFS.3mo.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "No Clearance" & circ_data$DFS.Event == TRUE & circ_data$DFS.3mo.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months 
          0.07907586 

#DFS by ctDNA Clearance ACT-treated at 6 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$ACT==TRUE,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 2
  ))

circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   106 observations deleted due to missingness 
                  n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 13      5     NA    5.52      NA
ctDNA.Dynamics=2  2      2   2.68    2.60      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Clearance from MRD to 6 months ACT-treated | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Clearance", "No Clearance"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

106 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      4       5    0.542   0.162        0.204        0.789
   24      2       0    0.542   0.162        0.204        0.789

                ctDNA.Dynamics=2 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2"), labels = c("Clearance", "No Clearance"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 15, number of events= 7 
   (106 observations deleted due to missingness)

                             coef exp(coef) se(coef)    z Pr(>|z|)  
ctDNA.DynamicsNo Clearance  3.017    20.438    1.237 2.44   0.0147 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsNo Clearance     20.44    0.04893      1.81     230.8

Concordance= 0.669  (se = 0.087 )
Likelihood ratio test= 5.94  on 1 df,   p=0.01
Wald test            = 5.95  on 1 df,   p=0.01
Score (logrank) test = 11.68  on 1 df,   p=6e-04
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 20.44 (1.81-230.77); p = 0.015"

#Percentages of MRD negative with molecular recurrence (returned positive) post-MRD

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD != "" & circ_data$Lead.Time >= 0, ]
circ_data <- circ_data[circ_data$ctDNA.MRD=="NEGATIVE",]
circ_data <- circ_data[circ_data$PostMRDPos.Event=="TRUE",]
circ_datadf <- as.data.frame(circ_data)

# Convert days to months
circ_data$PostMRDPos.months <- circ_data$PostMRDPos/30.437

# Define the intervals: 0-6, 6-9, 9-12, 12-15, 15-18, 18-21, 21-24, >24 months
breaks <- c(0, 6, 9, 12, 15, 18, 21, 24, 48)
labels <- c("0-6m", "6-9m", "9-12m", "12-15m", "15-18m", "18-21m", "21-24m", ">24m")

# Categorize p_drelReturned_months into intervals
circ_data$p_drelReturned_intervals <- cut(circ_data$PostMRDPos.months, breaks = breaks, labels = labels, right = FALSE)

# Examine the distribution of the intervals
table(circ_data$p_drelReturned_intervals)

  0-6m   6-9m  9-12m 12-15m 15-18m 18-21m 21-24m   >24m 
     9      5      7      1      4      0      0      0 
# Get the counts for each interval
interval_counts <- table(circ_data$p_drelReturned_intervals)

# Calculate the percentages
interval_percentages <- 100 * interval_counts / sum(interval_counts)

# Combine the counts and percentages for a clearer overview
interval_summary <- data.frame(Counts = interval_counts, Percentages = interval_percentages)

# Calculate the total number of observations
total_observations <- sum(interval_counts)

# Add the total number of observations to the summary
interval_summary$TotalObservations <- c(rep(NA, length(interval_counts)-1), total_observations)

# Print the summary with total observations
print(interval_summary)

# Calculate cumulative percentages
cumulative_percentages <- cumsum(interval_percentages)

# Combine the counts, percentages, and cumulative percentages for a clearer overview
interval_summary <- data.frame(Counts = interval_counts, Percentages = interval_percentages, CumulativePercentages = cumulative_percentages, TotalObservations = c(rep(NA, length(interval_counts)-1), total_observations))

bp <- barplot(interval_percentages, 
              main="Molecular Recurrence post-MRD in MRD negative patients", 
              xlab="Months Interval from Surgery", 
              ylab="Patients % converted positive", 
              col="lightblue",
              ylim=c(0, 100))

# Add the cumulative percentages to the plot
points(bp, cumulative_percentages, type="o", pch=22, col="red", cex=1.5)

print(interval_summary)

#DFS by ctDNA MRD positive vs ctDNA negative with molecular recurrence at Surveillance - 3 groups

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
survfit(Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   7 observations deleted due to missingness 
                   n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 180     10     NA      NA      NA
ctDNA.Dynamics=2  24     14  13.44   10.55      NA
ctDNA.Dynamics=3  35     25   9.27    7.62    14.1
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","green","red"), title="DFS - ctDNA MRD Pos vs Neg with Molecular Recurrence at Surveillance Window", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 239, number of events= 49 
   (7 observations deleted due to missingness)

                                      coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.DynamicsMolecular Recurrence  2.6086   13.5800   0.4162 6.267 3.68e-10 ***
ctDNA.DynamicsctDNA MRD Positive    3.2402   25.5396   0.3786 8.559  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                   exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsMolecular Recurrence     13.58    0.07364     6.006     30.70
ctDNA.DynamicsctDNA MRD Positive       25.54    0.03915    12.162     53.63

Concordance= 0.834  (se = 0.029 )
Likelihood ratio test= 94.98  on 2 df,   p=<2e-16
Wald test            = 74.17  on 2 df,   p=<2e-16
Score (logrank) test = 146.1  on 2 df,   p=<2e-16
#Fisher test for DFS percentages at 12 and 24 months - All time negative vs Molecular Recurrence
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "All-time negative")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        8.575063e-07         6.424306e-10 
#Repeat analysis to run Fisher test for All time negative vs ctDNA Positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]

surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log")
summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))

#Fisher test for DFS percentages at 12 and 24 months - All time negative vs ctDNA Positive
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "All-time negative")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "All-time negative" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        2.382798e-15         1.933852e-17 
#Repeat analysis to run Fisher test for Molecular Recurrence vs ctDNA Positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]

surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log")
summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

7 observations deleted due to missingness 
                ctDNA.Dynamics=1 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    131       7    0.959  0.0151        0.916         0.98
   24     28       2    0.942  0.0194        0.889         0.97

                ctDNA.Dynamics=2 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      10    0.569   0.104       0.3457        0.742
   24      2       4    0.285   0.122       0.0863        0.525

                ctDNA.Dynamics=3 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12      8      22    0.350  0.0830       0.1948        0.509
   24      2       3    0.219  0.0792       0.0884        0.386
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3"), labels = c("All-time negative","Molecular Recurrence", "ctDNA MRD Positive"))

#Fisher test for DFS percentages at 12 and 24 months - Molecular Recurrence vs ctDNA Positive
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Dynamics", "DFS.MRD.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.MRD.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence")
  pos_total <- sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Dynamics == "Molecular Recurrence" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Dynamics == "ctDNA MRD Positive" & circ_data$DFS.Event == 1 & circ_data$DFS.MRD.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
           0.1214065            0.4023373 
#Repeat to compare HRs for Molecular Recurrence vs ctDNA MRD positive
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="NEGATIVE" ~ 1,
    ctDNA.MRD == "NEGATIVE" & ctDNA.Surveillance=="POSITIVE" ~ 2,
    ctDNA.MRD == "POSITIVE" ~ 3
  ))

circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
surv_object <-Surv(time = circ_data$DFS.MRD.months, event = circ_data$DFS.Event)
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("2","3"), labels = c("Molecular Recurrence", "ctDNA MRD Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 59, number of events= 39 
   (187 observations deleted due to missingness)

                                   coef exp(coef) se(coef)     z Pr(>|z|)  
ctDNA.DynamicsctDNA MRD Positive 0.6281    1.8741   0.3361 1.869   0.0616 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                 exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsctDNA MRD Positive     1.874     0.5336    0.9699     3.621

Concordance= 0.608  (se = 0.037 )
Likelihood ratio test= 3.65  on 1 df,   p=0.06
Wald test            = 3.49  on 1 df,   p=0.06
Score (logrank) test = 3.6  on 1 df,   p=0.06
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 1.87 (0.97-3.62); p = 0.062"

#DFS by ctDNA at the Surveillance Window - All stages Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

survfit(Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)~ctDNA.Surveillance, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Surveillance, data = circ_data)

                              n events median 0.95LCL 0.95UCL
ctDNA.Surveillance=NEGATIVE 193     10     NA      NA      NA
ctDNA.Surveillance=POSITIVE  40     30   8.79    7.16      12
event_summary <- circ_data %>%
  group_by(ctDNA.Surveillance) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Surveillance, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","red"), title="DFS - ctDNA Surveillance window | All stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("ctDNA Negative", "ctDNA Positive"), legend.title="")

summary(KM_curve, times= c(12, 24))
Call: survfit(formula = surv_object ~ ctDNA.Surveillance, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

                ctDNA.Surveillance=NEGATIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12    138       8    0.955  0.0156        0.912        0.977
   24     31       1    0.946  0.0181        0.896        0.972

                ctDNA.Surveillance=POSITIVE 
 time n.risk n.event survival std.err lower 95% CI upper 95% CI
   12     12      26    0.336  0.0765       0.1940        0.485
   24      2       4    0.154  0.0733       0.0461        0.321
circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"))
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance, data=circ_data) 
ggforest(cox_fit,data = circ_data)

summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Surveillance, data = circ_data)

  n= 233, number of events= 40 

                              coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.SurveillancePOSITIVE  3.2170   24.9530   0.3726 8.633   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                           exp(coef) exp(-coef) lower .95 upper .95
ctDNA.SurveillancePOSITIVE     24.95    0.04008     12.02      51.8

Concordance= 0.822  (se = 0.033 )
Likelihood ratio test= 88.32  on 1 df,   p=<2e-16
Wald test            = 74.53  on 1 df,   p=<2e-16
Score (logrank) test = 156.3  on 1 df,   p=<2e-16
cox_fit_summary <- summary(cox_fit)

# Extract values for HR, 95% CI, and p-value
HR <- cox_fit_summary$coefficients[2]
lower_CI <- cox_fit_summary$conf.int[3]
upper_CI <- cox_fit_summary$conf.int[4]
p_value <- cox_fit_summary$coefficients[5]
label_text <- paste0("HR = ", round(HR, 2), " (", round(lower_CI, 2), "-", round(upper_CI, 2), "); p = ", round(p_value, 3))
print(label_text)
[1] "HR = 24.95 (12.02-51.8); p = 0"
#Fisher test for DFS percentages at 12 and 24 months
dfs_times <- c(12, 24)
circ_data <- na.omit(circ_data[, c("ctDNA.Surveillance", "DFS.months", "DFS.Event")])
p_values <- sapply(dfs_times, function(time) {
  neg_count <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  pos_count <- sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.months >= time & circ_data$DFS.Event == 0)
  neg_total <- sum(circ_data$ctDNA.Surveillance == "NEGATIVE")
  pos_total <- sum(circ_data$ctDNA.Surveillance == "POSITIVE")
  
  neg_surv <- neg_total - sum(circ_data$ctDNA.Surveillance == "NEGATIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  pos_surv <- pos_total - sum(circ_data$ctDNA.Surveillance == "POSITIVE" & circ_data$DFS.Event == 1 & circ_data$DFS.months < time)
  
  surv_matrix <- matrix(c(neg_surv, pos_surv, neg_total - neg_surv, pos_total - pos_surv), nrow = 2)
  test_result <- fisher.test(surv_matrix)
  return(test_result$p.value)
})
names(p_values) <- paste0("p-value at ", dfs_times, " months")
print(p_values)
p-value at 12 months p-value at 24 months 
        1.175567e-17         2.041854e-21 

#Multivariate cox regression at Surveillance Window for DFS - All stages Landmark 10 weeks

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.Surveillance!="",]
circ_data$DFS.months=circ_data$DFS.months-2.5
circ_data <- circ_data[circ_data$DFS.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Surveillance <- factor(circ_data$ctDNA.Surveillance, levels=c("NEGATIVE","POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Gender <- factor(circ_data$Gender, levels = c("Female", "Male"))
circ_data$Age.Group <- factor(circ_data$Age.Group, levels = c("1", "2"), labels = c("<70", ">70"))
circ_data$PrimSite <- factor(circ_data$PrimSite, levels = c("Left-sided colon", "Right-sided colon"))
circ_data$ECOG <- factor(circ_data$ECOG, levels = c("0", "1"))
circ_data$pT <- factor(circ_data$pT, levels = c("T1-T2", "T3-T4"))
circ_data$pN <- factor(circ_data$pN, levels = c("N0", "N1-N2"))
circ_data$LVI <- factor(circ_data$LVI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No"))
circ_data$PNI <- factor(circ_data$PNI, levels = c("TRUE", "FALSE"), labels = c("Yes", "No"))
circ_data$Grade <- factor(circ_data$Grade, levels = c("G1", "G2/G3"))
circ_data$RAS <- factor(circ_data$RAS, levels = c("WT", "MUT"), labels = c("Wild-Type", "Mutant"))
surv_object <- Surv(time = circ_data$DFS.months, event = circ_data$DFS.Event) 
cox_fit <- coxph(surv_object ~ ctDNA.Surveillance + Gender + Age.Group + ECOG + pT + pN + LVI + PNI + Grade + RAS, data=circ_data) 
ggforest(cox_fit, data = circ_data, main = "Multivariate Regression Model for DFS - All Stages", refLabel = "Reference Group")

test.ph <- cox.zph(cox_fit)

#DFS by ctDNA Dynamics from MRD to 6 months - all stages

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.6mo.months>=0,]
circ_datadf <- as.data.frame(circ_data)

circ_data$ctDNA.Dynamics <- NA #first we create the variable for the ctDNA & NAC combination, and we assign values
circ_data <- circ_data %>%
  mutate(ctDNA.Dynamics = case_when(
    ctDNA.MRD == "NEGATIVE" & ctDNA.6months == "NEGATIVE" ~ 1,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "NEGATIVE" ~ 2,
    ctDNA.MRD == "NEGATIVE" & ctDNA.6months == "POSITIVE" ~ 3,
    ctDNA.MRD == "POSITIVE" & ctDNA.6months == "POSITIVE" ~ 4
  ))

survfit(Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)~ctDNA.Dynamics, data = circ_data)
Call: survfit(formula = Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event) ~ 
    ctDNA.Dynamics, data = circ_data)

   66 observations deleted due to missingness 
                   n events median 0.95LCL 0.95UCL
ctDNA.Dynamics=1 157     16     NA      NA      NA
ctDNA.Dynamics=2  14      5     NA    5.52      NA
ctDNA.Dynamics=3   4      2   8.51    0.00      NA
ctDNA.Dynamics=4   5      5   2.76    2.60      NA
event_summary <- circ_data %>%
  group_by(ctDNA.Dynamics) %>%
  summarise(
    Total = n(),
    Events = sum(DFS.Event),
    Fraction = Events / n(),
    Percentage = (Events / n()) * 100
  )
print(event_summary)
surv_object <-Surv(time = circ_data$DFS.6mo.months, event = circ_data$DFS.Event)
KM_curve <- survfit(surv_object ~ ctDNA.Dynamics, data = circ_data,conf.int=0.95,conf.type="log-log") 
ggsurvplot(KM_curve, data = circ_data, pval = FALSE, conf.int = FALSE, risk.table = TRUE, break.time.by=6, palette=c("blue","green","purple", "red"), title="DFS - ctDNA Dynamics from MRD to 6 months | All Stages", ylab= "Disease-Free Survival", xlab="Time from Landmark Time point (Months)", legend.labs=c("Persistently Negative", "Converted Negative","Converted Positive", "Persistently Positive"), legend.title="")
summary(KM_curve, times= c(24))
Call: survfit(formula = surv_object ~ ctDNA.Dynamics, data = circ_data, 
    conf.int = 0.95, conf.type = "log-log")

66 observations deleted due to missingness 
                ctDNA.Dynamics=1 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000       12.000       16.000        0.851        0.045        0.736        0.919 

                ctDNA.Dynamics=2 
        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI 
      24.000        2.000        5.000        0.542        0.162        0.204        0.789 

                ctDNA.Dynamics=3 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI

                ctDNA.Dynamics=4 
     time n.risk n.event survival std.err lower 95% CI upper 95% CI
circ_data$ctDNA.Dynamics <- factor(circ_data$ctDNA.Dynamics, levels=c("1","2","3", "4"), labels = c("Persistently Negative", "Converted Negative","Converted Positive", "Persistently Positive"))
cox_fit <- coxph(surv_object ~ ctDNA.Dynamics, data=circ_data) 
ggforest(cox_fit,data = circ_data) 
summary(cox_fit)
Call:
coxph(formula = surv_object ~ ctDNA.Dynamics, data = circ_data)

  n= 180, number of events= 28 
   (66 observations deleted due to missingness)

                                       coef exp(coef) se(coef)     z Pr(>|z|)    
ctDNA.DynamicsConverted Negative     1.5689    4.8013   0.5147 3.048  0.00230 ** 
ctDNA.DynamicsConverted Positive     2.1062    8.2170   0.7582 2.778  0.00547 ** 
ctDNA.DynamicsPersistently Positive  3.8173   45.4828   0.5900 6.470  9.8e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

                                    exp(coef) exp(-coef) lower .95 upper .95
ctDNA.DynamicsConverted Negative        4.801    0.20828     1.751     13.17
ctDNA.DynamicsConverted Positive        8.217    0.12170     1.859     36.32
ctDNA.DynamicsPersistently Positive    45.483    0.02199    14.310    144.57

Concordance= 0.697  (se = 0.048 )
Likelihood ratio test= 33.4  on 3 df,   p=3e-07
Wald test            = 46.4  on 3 df,   p=5e-10
Score (logrank) test = 106.2  on 3 df,   p=<2e-16

#Table with recurrence sites by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data_subset1 <- circ_data %>%
  select(
    Rel.Site) %>%
  mutate(
    Rel.Site = factor(Rel.Site, levels = c("Local", "Lymph Node", "Liver", "Lung", "Peritoneum", "Brain")))

circ_data_subset2 <- circ_data %>%
  select(
    Rel.Site,
    ctDNA.MRD) %>%
  mutate(
    Rel.Site = factor(Rel.Site, levels = c("Local", "Lymph Node", "Liver", "Lung", "Peritoneum", "Brain")),
    ctDNA.MRD = factor(ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE")))
Overall <- circ_data_subset1 %>%
  tbl_summary(
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  bold_labels()
Overall
Characteristic N = 481
Rel.Site
    Local 4 (8.3%)
    Lymph Node 5 (10%)
    Liver 17 (35%)
    Lung 18 (38%)
    Peritoneum 3 (6.3%)
    Brain 1 (2.1%)
1 n (%)

ByctDNA_MRD <- circ_data_subset2 %>%
  tbl_summary(
    by = ctDNA.MRD, # add this line to subgroup by ctDNA.MRD
    statistic = list(
      all_continuous() ~ "{median} ({min} - {max})",
      all_categorical() ~ "{n} ({p}%)")) %>%
  add_p() %>%
  bold_labels()
ByctDNA_MRD
Characteristic NEGATIVE
N = 23
1
POSITIVE
N = 25
1
p-value2
Rel.Site

<0.001
    Local 2 (8.7%) 2 (8.0%)
    Lymph Node 1 (4.3%) 4 (16%)
    Liver 2 (8.7%) 15 (60%)
    Lung 15 (65%) 3 (12%)
    Peritoneum 2 (8.7%) 1 (4.0%)
    Brain 1 (4.3%) 0 (0%)
1 n (%)
2 Fisher’s exact test

merged_table <- tbl_merge(tbls=list(Overall, ByctDNA_MRD))
merged_table
Characteristic
Table 1
Table 2
N = 481 NEGATIVE
N = 23
1
POSITIVE
N = 25
1
p-value2
Rel.Site


<0.001
    Local 4 (8.3%) 2 (8.7%) 2 (8.0%)
    Lymph Node 5 (10%) 1 (4.3%) 4 (16%)
    Liver 17 (35%) 2 (8.7%) 15 (60%)
    Lung 18 (38%) 15 (65%) 3 (12%)
    Peritoneum 3 (6.3%) 2 (8.7%) 1 (4.0%)
    Brain 1 (2.1%) 1 (4.3%) 0 (0%)
1 n (%)
2 Fisher’s exact test

fit1 <- as_flex_table(
  merged_table,
  include = everything(),
  return_calls = FALSE)
fit1

Table 1

Table 2

Characteristic

N = 481

NEGATIVE
N = 231

POSITIVE
N = 251

p-value2

Rel.Site

<0.001

Local

4 (8.3%)

2 (8.7%)

2 (8.0%)

Lymph Node

5 (10%)

1 (4.3%)

4 (16%)

Liver

17 (35%)

2 (8.7%)

15 (60%)

Lung

18 (38%)

15 (65%)

3 (12%)

Peritoneum

3 (6.3%)

2 (8.7%)

1 (4.0%)

Brain

1 (2.1%)

1 (4.3%)

0 (0%)

1n (%)

2Fisher's exact test

save_as_docx(fit1, path= "~/Downloads/merged_table.docx")

#MTM/mL levels at the MRD Window by Radiological Recurrence

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- as.data.frame(circ_data)

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$RFS.Event <- factor(circ_data$RFS.Event, levels = c("FALSE", "TRUE"), labels = c("No Recurrence", "Recurrence"))
summary_stats <- circ_data %>%
  group_by(RFS.Event) %>%
  summarise(
    median_p_MRD_MTM = median(p_MRD_MTM, na.rm = TRUE),
    range_p_MRD_MTM = paste0(min(p_MRD_MTM, na.rm = TRUE), " - ", max(p_MRD_MTM, na.rm = TRUE))
  )
print(summary_stats)

m3_1v2 <- wilcox.test(p_MRD_MTM ~ RFS.Event,
                      data = circ_data[circ_data$RFS.Event %in% c("No Recurrence", "Recurrence"), ],
                      na.rm = TRUE)
print(m3_1v2)

    Wilcoxon rank sum test with continuity correction

data:  p_MRD_MTM by RFS.Event
W = 2458, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
boxplot(p_MRD_MTM~RFS.Event, data=circ_data, main="ctDNA MRD Window MTM - Recurrence", xlab="Recurrence", ylab="MTM/mL", col="white",border="black", ylim = c(0, 50))

#MTM/mL levels at the MRD Window by Radiological Recurrence Sites

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]
circ_data <- circ_data[circ_data$ctDNA.MRD!="",]
circ_data <- circ_data[circ_data$DFS.MRD.months>=0,]
circ_data <- as.data.frame(circ_data)

# Transform p_MRD_MTM with log10
circ_data$p_MRD_MTM <- as.numeric(as.character(circ_data$p_MRD_MTM))
circ_data$Rel.Site <- factor(circ_data$Rel.Site, levels = c("Liver", "Lymph Node", "Local", "Peritoneum", "Lung", "Brain"))
summary_stats <- circ_data %>%
  group_by(Rel.Site) %>%
  summarise(
    median_p_MRD_MTM = median(p_MRD_MTM, na.rm = TRUE),
    range_p_MRD_MTM = paste0(min(p_MRD_MTM, na.rm = TRUE), " - ", max(p_MRD_MTM, na.rm = TRUE))
  )
print(summary_stats)
kruskal_test <- kruskal.test(p_MRD_MTM ~ Rel.Site, data = circ_data)
print(kruskal_test)

    Kruskal-Wallis rank sum test

data:  p_MRD_MTM by Rel.Site
Kruskal-Wallis chi-squared = 20.366, df = 5, p-value = 0.001067
boxplot(p_MRD_MTM~Rel.Site, data=circ_data, main="ctDNA MRD Window MTM - Recurrence Site", xlab="Recurrence Site", ylab="MTM/mL", col="white",border="black", ylim = c(0, 40))

#Barplot with Recurrence Sites (Liver vs Others) by ctDNA at the MRD Window

rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

circ_data$ctDNA.MRD <- factor(circ_data$ctDNA.MRD, levels = c("NEGATIVE", "POSITIVE"), labels = c("Negative", "Positive"))
circ_data$Rel.Site <- factor(circ_data$Rel.Site, levels = c("Liver", "Lymph Node", "Local", "Peritoneum", "Lung", "Brain"))
contingency_table <- table(circ_data$Rel.Site, circ_data$ctDNA.MRD)
chi_square_test <- chisq.test(contingency_table)
Warning: Chi-squared approximation may be incorrect
print(chi_square_test)

    Pearson's Chi-squared test

data:  contingency_table
X-squared = 21.028, df = 5, p-value = 0.0008004
fisher_exact_test <- fisher.test(contingency_table)
print(fisher_exact_test)

    Fisher's Exact Test for Count Data

data:  contingency_table
p-value = 5.02e-05
alternative hypothesis: two.sided
print(contingency_table)
            
             Negative Positive
  Liver             2       15
  Lymph Node        1        4
  Local             2        2
  Peritoneum        2        1
  Lung             15        3
  Brain             1        0
table_df <- as.data.frame(contingency_table)
table_df$Total <- ave(table_df$Freq, table_df$Var1, FUN = sum)
table_df$Percentage <- table_df$Freq / table_df$Total
table_df$MiddlePercentage <- table_df$Percentage / 2
ggplot(table_df, aes(x = Var1, y = Percentage, fill = Var2)) +
  geom_bar(stat = "identity") +
  geom_text(aes(y = MiddlePercentage, label = Freq), position = "stack", color = "black", vjust = 1.5, size = 7) +
  theme_minimal() +
  labs(title = "Patients with Radiological Recurrence", 
       x = "Recurrence Site", 
       y = "Patients (%)", 
       fill = "ctDNA at MRD",
       caption = paste("Chi-squared test p-value: ", format.pval(chi_square_test$p.value))) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Negative" = "blue", "Positive" = "red")) + # define custom colors
  theme(axis.text.x = element_text(angle = 0, hjust = 1.5, size = 14), # increase x-axis text size
        axis.text.y = element_text(size = 14, color = "black"), # increase y-axis text size
        axis.title.x = element_text(size = 14, color = "black"), # increase x-axis label size
        axis.title.y = element_text(size = 14, color = "black"), # increase y-axis label size
        legend.text = element_text(size = 12, color = "black"))  # increase Recurrence label size

#Detection ctDNA rates based on sites of relapse

# Remove existing objects and set the working directory
rm(list=ls())
setwd("~/Downloads")
circ_data <- read.csv("Galaxy Data_20240603 Complete Dataset.csv")
circ_data <- circ_data[circ_data$CohortB=="TRUE",]
circ_data <- circ_data[circ_data$RFS.Event=="TRUE",]

# Create a table of counts for the "Rel.Site" variable
relsite_counts <- table(circ_data$Rel.Site)
relsite_df <- as.data.frame(relsite_counts)
names(relsite_df) <- c("Rel.Site", "Count")
circ_data_pos_mrd <- circ_data[circ_data$ctDNA.MRD=="POSITIVE",]
circ_data_pos_anytime <- circ_data[circ_data$ctDNA.anytime=="POSITIVE",]
pos_counts_mrd <- table(circ_data_pos_mrd$Rel.Site)
pos_counts_anytime <- table(circ_data_pos_anytime$Rel.Site)
relsite_df$MRDPos_Count <- ifelse(is.na(match(relsite_df$Rel.Site, names(pos_counts_mrd))), 0, pos_counts_mrd[match(relsite_df$Rel.Site, names(pos_counts_mrd))])
relsite_df$MRDPos_Count[is.na(relsite_df$MRDPos_Count)] <- 0
relsite_df$AnytimePos_Count <- ifelse(is.na(match(relsite_df$Rel.Site, names(pos_counts_anytime))), 0, pos_counts_anytime[match(relsite_df$Rel.Site, names(pos_counts_anytime))])
relsite_df$AnytimePos_Count[is.na(relsite_df$AnytimePos_Count)] <- 0
relsite_df$Percent <- (relsite_df$Count / sum(relsite_df$Count)) * 100
relsite_df$MRDPos_Percent <- (relsite_df$MRDPos_Count / relsite_df$Count) * 100
relsite_df$AnytimePos_Percent <- (relsite_df$AnytimePos_Count / relsite_df$Count) * 100
total_observations <- sum(relsite_df$Count)
total_pos_mrd <- sum(relsite_df$MRDPos_Count)
total_pos_anytime <- sum(relsite_df$AnytimePos_Count)
total_row <- data.frame(Rel.Site = "Total", Count = total_observations, MRDPos_Count = total_pos_mrd, AnytimePos_Count = total_pos_anytime, Percent = 100, MRDPos_Percent = (total_pos_mrd / total_observations) * 100, AnytimePos_Percent = (total_pos_anytime / total_observations) * 100)
relsite_df <- rbind(relsite_df, total_row)
print(relsite_df)

ft <- flextable(relsite_df)
doc <- read_docx() %>%
  body_add_flextable(value = ft)
print(doc, target = "relsite_df.docx")
LS0tCnRpdGxlOiAiQ0lSQ1VMQVRFIEdhbGF4eSBjb2hvcnQgQiBBbmRvIGV0IGFsIDIwMjQiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmxpYnJhcnkoc3dpbXBsb3QpCmxpYnJhcnkoY294cGhmKQpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3RhYmxlKQpsaWJyYXJ5KHJlYWRyKSAKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkob2ZmaWNlcikKbGlicmFyeShmbGV4dGFibGUpCmxpYnJhcnkoc3Vydml2YWwpIApsaWJyYXJ5KHN1cnZtaW5lcikKbGlicmFyeShncmlkdGV4dCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3RzdW1tYXJ5KQpsaWJyYXJ5KGZsZXh0YWJsZSkKbGlicmFyeShwYXJhbWV0ZXJzKQpsaWJyYXJ5KGNhcikKbGlicmFyeShncmlkKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHJtcykKbGlicmFyeShEVCkKCiNEZW1vZ3JhcGhpY3MgVGFibGUKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCgpjaXJjX2RhdGFfc3Vic2V0IDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgcFQsCiAgICBwTiwKICAgIExWSSwKICAgIFBOSSwKICAgIEdyYWRlLAogICAgTG9jYXRpb24sCiAgICBTdXJnLlR5cGUsCiAgICBTdGFnZSwKICAgIEFDVCwKICAgIEJSQUYuVjYwMEUsCiAgICBSQVMsCiAgICBNU0ksCiAgICBSRlMuRXZlbnQsCiAgICBPUy5FdmVudCwKICAgIE9TLm1vbnRocykgJT4lCiAgbXV0YXRlKAogICAgQWdlID0gYXMubnVtZXJpYyhBZ2UpLAogICAgR2VuZGVyID0gZmFjdG9yKEdlbmRlciwgbGV2ZWxzID0gYygiTWFsZSIsICJGZW1hbGUiKSksCiAgICBFQ09HID0gZmFjdG9yKEVDT0csIGxldmVscyA9IGMoMCwgMSkpLAogICAgcFQgPSBmYWN0b3IocFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpLAogICAgcE4gPSBmYWN0b3IocE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpLAogICAgTFZJID0gZmFjdG9yKExWSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSksCiAgICBQTkkgPSBmYWN0b3IoUE5JLCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlllcyIsICJObyIpKSwKICAgIEdyYWRlID0gZmFjdG9yKEdyYWRlLCBsZXZlbHMgPSBjKCJHMSIsICJHMi9HMyIpKSwKICAgIExvY2F0aW9uID0gZmFjdG9yKExvY2F0aW9uLCBsZXZlbHMgPSBjKCJVcHBlciByZWN0dW0gKFJhKSIsICJMb3dlciByZWN0dW0gKFJiKSIpKSwKICAgIFN1cmcuVHlwZSA9IGZhY3RvcihTdXJnLlR5cGUpLAogICAgU3RhZ2UgPSBmYWN0b3IoU3RhZ2UsIGxldmVscyA9IGMoIklJIiwgIklJSSIpKSwKICAgIEFDVCA9IGZhY3RvcihBQ1QsIGxldmVscyA9IGMoIlRSVUUiLCAiRkFMU0UiKSwgbGFiZWxzID0gYygiQWRqdXZhbnQgQ2hlbW90aGVyYXB5IiwgIk9ic2VydmF0aW9uIikpLAogICAgQlJBRi5WNjAwRSA9IGZhY3RvcihCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiQlJBRiB3dCIsICJCUkFGIFY2MDBFIikpLAogICAgUkFTID0gZmFjdG9yKFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIlJBUyB3dCIsICJSQVMgbXV0IikpLAogICAgTVNJID0gZmFjdG9yKE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpLAogICAgUkZTLkV2ZW50ID0gZmFjdG9yKFJGUy5FdmVudCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJSZWN1cnJlbmNlIiwgIk5vIFJlY3VycmVuY2UiKSksCiAgICBPUy5FdmVudCA9IGZhY3RvcihPUy5FdmVudCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJEZWNlYXNlZCIsICJBbGl2ZSIpKSwKICAgIE9TLm1vbnRocyA9IGFzLm51bWVyaWMoT1MubW9udGhzKSkKdGFibGUxIDwtIGNpcmNfZGF0YV9zdWJzZXQgJT4lCiAgdGJsX3N1bW1hcnkoCiAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICBhbGxfY29udGludW91cygpIH4gInttZWRpYW59ICh7bWlufSAtIHttYXh9KSIsCiAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAoe3B9JSkiKSkgJT4lCiAgYm9sZF9sYWJlbHMoKQp0YWJsZTEKZml0MSA8LSBhc19mbGV4X3RhYmxlKAogIHRhYmxlMSwKICBpbmNsdWRlID0gZXZlcnl0aGluZygpLAogIHJldHVybl9jYWxscyA9IEZBTFNFKQpmaXQxCnNhdmVfYXNfZG9jeChmaXQxLCBwYXRoPSAifi9Eb3dubG9hZHMvdGFibGUxLmRvY3giKQpgYGAKCgojRGVtb2dyYXBoaWNzIFRhYmxlIGJ5IE1SRCBjdEROQSBTdGF0dXMKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQoKY2lyY19kYXRhX3N1YnNldDEgPC0gY2lyY19kYXRhICU+JQogIHNlbGVjdCgKICAgIEFnZSwKICAgIEdlbmRlciwKICAgIEVDT0csCiAgICBwVCwKICAgIHBOLAogICAgTFZJLAogICAgUE5JLAogICAgR3JhZGUsCiAgICBMb2NhdGlvbiwKICAgIFN1cmcuVHlwZSwKICAgIFN0YWdlLAogICAgQUNULAogICAgQlJBRi5WNjAwRSwKICAgIFJBUywKICAgIE1TSSwKICAgIFJGUy5FdmVudCwKICAgIE9TLkV2ZW50LAogICAgT1MubW9udGhzKSAlPiUKICBtdXRhdGUoCiAgICBBZ2UgPSBhcy5udW1lcmljKEFnZSksCiAgICBHZW5kZXIgPSBmYWN0b3IoR2VuZGVyLCBsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKSwKICAgIEVDT0cgPSBmYWN0b3IoRUNPRywgbGV2ZWxzID0gYygwLCAxKSksCiAgICBwVCA9IGZhY3RvcihwVCwgbGV2ZWxzID0gYygiVDEtVDIiLCAiVDMtVDQiKSksCiAgICBwTiA9IGZhY3RvcihwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSksCiAgICBMVkkgPSBmYWN0b3IoTFZJLCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlllcyIsICJObyIpKSwKICAgIFBOSSA9IGZhY3RvcihQTkksIGxldmVscyA9IGMoIlRSVUUiLCAiRkFMU0UiKSwgbGFiZWxzID0gYygiWWVzIiwgIk5vIikpLAogICAgR3JhZGUgPSBmYWN0b3IoR3JhZGUsIGxldmVscyA9IGMoIkcxIiwgIkcyL0czIikpLAogICAgTG9jYXRpb24gPSBmYWN0b3IoTG9jYXRpb24sIGxldmVscyA9IGMoIlVwcGVyIHJlY3R1bSAoUmEpIiwgIkxvd2VyIHJlY3R1bSAoUmIpIikpLAogICAgU3VyZy5UeXBlID0gZmFjdG9yKFN1cmcuVHlwZSksCiAgICBTdGFnZSA9IGZhY3RvcihTdGFnZSwgbGV2ZWxzID0gYygiSUkiLCAiSUlJIikpLAogICAgQUNUID0gZmFjdG9yKEFDVCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJBZGp1dmFudCBDaGVtb3RoZXJhcHkiLCAiT2JzZXJ2YXRpb24iKSksCiAgICBCUkFGLlY2MDBFID0gZmFjdG9yKEJSQUYuVjYwMEUsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJCUkFGIHd0IiwgIkJSQUYgVjYwMEUiKSksCiAgICBSQVMgPSBmYWN0b3IoUkFTLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiUkFTIHd0IiwgIlJBUyBtdXQiKSksCiAgICBNU0kgPSBmYWN0b3IoTVNJLCBsZXZlbHMgPSBjKCJNU1MiLCAiTVNJLUhpZ2giKSksCiAgICBSRlMuRXZlbnQgPSBmYWN0b3IoUkZTLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlJlY3VycmVuY2UiLCAiTm8gUmVjdXJyZW5jZSIpKSwKICAgIE9TLkV2ZW50ID0gZmFjdG9yKE9TLkV2ZW50LCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIkRlY2Vhc2VkIiwgIkFsaXZlIikpLAogICAgT1MubW9udGhzID0gYXMubnVtZXJpYyhPUy5tb250aHMpKQoKY2lyY19kYXRhMSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KCmNpcmNfZGF0YV9zdWJzZXQyIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBBZ2UsCiAgICBHZW5kZXIsCiAgICBFQ09HLAogICAgcFQsCiAgICBwTiwKICAgIExWSSwKICAgIFBOSSwKICAgIEdyYWRlLAogICAgTG9jYXRpb24sCiAgICBTdXJnLlR5cGUsCiAgICBTdGFnZSwKICAgIEFDVCwKICAgIEJSQUYuVjYwMEUsCiAgICBSQVMsCiAgICBNU0ksCiAgICBSRlMuRXZlbnQsCiAgICBPUy5FdmVudCwKICAgIE9TLm1vbnRocywKICAgIGN0RE5BLk1SRCkgJT4lCiAgbXV0YXRlKAogICAgQWdlID0gYXMubnVtZXJpYyhBZ2UpLAogICAgR2VuZGVyID0gZmFjdG9yKEdlbmRlciwgbGV2ZWxzID0gYygiTWFsZSIsICJGZW1hbGUiKSksCiAgICBFQ09HID0gZmFjdG9yKEVDT0csIGxldmVscyA9IGMoMCwgMSkpLAogICAgcFQgPSBmYWN0b3IocFQsIGxldmVscyA9IGMoIlQxLVQyIiwgIlQzLVQ0IikpLAogICAgcE4gPSBmYWN0b3IocE4sIGxldmVscyA9IGMoIk4wIiwgIk4xLU4yIikpLAogICAgTFZJID0gZmFjdG9yKExWSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSksCiAgICBQTkkgPSBmYWN0b3IoUE5JLCBsZXZlbHMgPSBjKCJUUlVFIiwgIkZBTFNFIiksIGxhYmVscyA9IGMoIlllcyIsICJObyIpKSwKICAgIEdyYWRlID0gZmFjdG9yKEdyYWRlLCBsZXZlbHMgPSBjKCJHMSIsICJHMi9HMyIpKSwKICAgIExvY2F0aW9uID0gZmFjdG9yKExvY2F0aW9uLCBsZXZlbHMgPSBjKCJVcHBlciByZWN0dW0gKFJhKSIsICJMb3dlciByZWN0dW0gKFJiKSIpKSwKICAgIFN1cmcuVHlwZSA9IGZhY3RvcihTdXJnLlR5cGUpLAogICAgU3RhZ2UgPSBmYWN0b3IoU3RhZ2UsIGxldmVscyA9IGMoIklJIiwgIklJSSIpKSwKICAgIEFDVCA9IGZhY3RvcihBQ1QsIGxldmVscyA9IGMoIlRSVUUiLCAiRkFMU0UiKSwgbGFiZWxzID0gYygiQWRqdXZhbnQgQ2hlbW90aGVyYXB5IiwgIk9ic2VydmF0aW9uIikpLAogICAgQlJBRi5WNjAwRSA9IGZhY3RvcihCUkFGLlY2MDBFLCBsZXZlbHMgPSBjKCJXVCIsICJNVVQiKSwgbGFiZWxzID0gYygiQlJBRiB3dCIsICJCUkFGIFY2MDBFIikpLAogICAgUkFTID0gZmFjdG9yKFJBUywgbGV2ZWxzID0gYygiV1QiLCAiTVVUIiksIGxhYmVscyA9IGMoIlJBUyB3dCIsICJSQVMgbXV0IikpLAogICAgTVNJID0gZmFjdG9yKE1TSSwgbGV2ZWxzID0gYygiTVNTIiwgIk1TSS1IaWdoIikpLAogICAgUkZTLkV2ZW50ID0gZmFjdG9yKFJGUy5FdmVudCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJSZWN1cnJlbmNlIiwgIk5vIFJlY3VycmVuY2UiKSksCiAgICBPUy5FdmVudCA9IGZhY3RvcihPUy5FdmVudCwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJEZWNlYXNlZCIsICJBbGl2ZSIpKSwKICAgIE9TLm1vbnRocyA9IGFzLm51bWVyaWMoT1MubW9udGhzKSwKICAgIGN0RE5BLk1SRCA9IGZhY3RvcihjdEROQS5NUkQsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIikpKQpPdmVyYWxsIDwtIGNpcmNfZGF0YV9zdWJzZXQxICU+JQogIHRibF9zdW1tYXJ5KAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGJvbGRfbGFiZWxzKCkKT3ZlcmFsbAoKQnljdEROQV9NUkQgPC0gY2lyY19kYXRhX3N1YnNldDIgJT4lCiAgdGJsX3N1bW1hcnkoCiAgICBieSA9IGN0RE5BLk1SRCwgIyBhZGQgdGhpcyBsaW5lIHRvIHN1Ymdyb3VwIGJ5IGN0RE5BLk1SRAogICAgc3RhdGlzdGljID0gbGlzdCgKICAgICAgYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVkaWFufSAoe21pbn0gLSB7bWF4fSkiLAogICAgICBhbGxfY2F0ZWdvcmljYWwoKSB+ICJ7bn0gKHtwfSUpIikpICU+JQogIGFkZF9wKCkgJT4lCiAgYm9sZF9sYWJlbHMoKQpCeWN0RE5BX01SRAoKbWVyZ2VkX3RhYmxlIDwtIHRibF9tZXJnZSh0YmxzPWxpc3QoT3ZlcmFsbCwgQnljdEROQV9NUkQpKQptZXJnZWRfdGFibGUKCmZpdDEgPC0gYXNfZmxleF90YWJsZSgKICBtZXJnZWRfdGFibGUsCiAgaW5jbHVkZSA9IGV2ZXJ5dGhpbmcoKSwKICByZXR1cm5fY2FsbHMgPSBGQUxTRSkKZml0MQpzYXZlX2FzX2RvY3goZml0MSwgcGF0aD0gIn4vRG93bmxvYWRzL21lcmdlZF90YWJsZS5kb2N4IikKYGBgCgojREZTIGluIENvbXBsZXRlIENvaG9ydCAoTj0yNTApCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpIApjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Q29ob3J0QiwgZGF0YSA9IGNpcmNfZGF0YSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gQ29ob3J0QiwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIpLCB0aXRsZT0iREZTIC0gQ29tcGxldGUgQ29ob3J0IChuPTI1MCkiLCB5bGFiPSAiUHJvZ3Jlc3Npb24tRnJlZSBTdXJ2aXZhbCIsIHhsYWI9Ik1vbnRocyBmcm9tIFN1cmdlcnkiLCBsZWdlbmQubGFicz1jKCJDb21wbGV0ZSBjb2hvcnQiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQsIDM2KSkKYGBgCgojT1MgaW4gQ29tcGxldGUgQ29ob3J0IChOPTI1MCkKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikgCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkT1MubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCl+Q29ob3J0QiwgZGF0YSA9IGNpcmNfZGF0YSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkT1MubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRPUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IENvaG9ydEIsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiKSwgdGl0bGU9Ik9TIC0gQ29tcGxldGUgQ29ob3J0IChuPTI1MCkiLCB5bGFiPSAiT3ZlcmFsbCBTdXJ2aXZhbCIsIHhsYWI9Ik1vbnRocyBmcm9tIFN1cmdlcnkiLCBsZWdlbmQubGFicz1jKCJDb21wbGV0ZSBjb2hvcnQiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQsIDM2KSkKYGBgCgojY3RETkEgRGV0ZWN0aW9uIFJhdGVzIGJ5IFdpbmRvdyBhbmQgU3RhZ2VzCmBgYHtyfQojY3RETkEgYXQgQmFzZWxpbmUKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSA8LSBzdWJzZXQoY2lyY19kYXRhLCBjdEROQS5CYXNlbGluZSAlaW4lIGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRTdGFnZSA8LSBmYWN0b3IoY2lyY19kYXRhJFN0YWdlLCBsZXZlbHM9YygiSUkiLCAiSUlJIikpCnBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSA8LSBhZ2dyZWdhdGUoY2lyY19kYXRhJGN0RE5BLkJhc2VsaW5lID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuQmFzZWxpbmUgPT0gIlBPU0lUSVZFIixdKQpvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSA8LSAob3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCAvIG92ZXJhbGxfdG90YWxfY291bnQpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQpvdmVyYWxsX3JvdyA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gIk92ZXJhbGwiLAogIFRvdGFsX0NvdW50ID0gb3ZlcmFsbF90b3RhbF9jb3VudCwKICBQb3NpdGl2ZV9Db3VudCA9IG92ZXJhbGxfcG9zaXRpdmVfY291bnQsCiAgUmF0ZSA9IHNwcmludGYoIiUuMmYlJSIsIG92ZXJhbGxfcG9zaXRpdml0eV9yYXRlKQopCmNvbWJpbmVkX2RhdGEgPC0gcmJpbmQoY29tYmluZWRfZGF0YSwgb3ZlcmFsbF9yb3cpCnByaW50KGNvbWJpbmVkX2RhdGEpCgojY3RETkEgYXQgTVJEIFdpbmRvdwpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzPWMoIk5FR0FUSVZFIiwiUE9TSVRJVkUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscz1jKCJJSSIsICJJSUkiKSkKcG9zaXRpdmVfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPXN1bSkKdG90YWxfY291bnRzX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjaXJjX2RhdGEkY3RETkEuTVJELCBieT1saXN0KGNpcmNfZGF0YSRTdGFnZSksIEZVTj1sZW5ndGgpCmNvbWJpbmVkX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9IHRvdGFsX2NvdW50c19ieV9zdGFnZSRHcm91cC4xLAogIFRvdGFsX0NvdW50ID0gdG90YWxfY291bnRzX2J5X3N0YWdlJHgsCiAgUG9zaXRpdmVfQ291bnQgPSBwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UkeCwKICBSYXRlID0gKHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4IC8gdG90YWxfY291bnRzX2J5X3N0YWdlJHgpICogMTAwICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQopCmNvbWJpbmVkX2RhdGEkUmF0ZSA8LSBzcHJpbnRmKCIlLjJmJSUiLCBjb21iaW5lZF9kYXRhJFJhdGUpCm92ZXJhbGxfdG90YWxfY291bnQgPC0gbnJvdyhjaXJjX2RhdGEpCm92ZXJhbGxfcG9zaXRpdmVfY291bnQgPC0gbnJvdyhjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiLF0pCm92ZXJhbGxfcG9zaXRpdml0eV9yYXRlIDwtIChvdmVyYWxsX3Bvc2l0aXZlX2NvdW50IC8gb3ZlcmFsbF90b3RhbF9jb3VudCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCm92ZXJhbGxfcm93IDwtIGRhdGEuZnJhbWUoCiAgU3RhZ2UgPSAiT3ZlcmFsbCIsCiAgVG90YWxfQ291bnQgPSBvdmVyYWxsX3RvdGFsX2NvdW50LAogIFBvc2l0aXZlX0NvdW50ID0gb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCwKICBSYXRlID0gc3ByaW50ZigiJS4yZiUlIiwgb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUpCikKY29tYmluZWRfZGF0YSA8LSByYmluZChjb21iaW5lZF9kYXRhLCBvdmVyYWxsX3JvdykKcHJpbnQoY29tYmluZWRfZGF0YSkKCiNjdEROQSBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNpcmNfZGF0YSA8LSBzdWJzZXQoY2lyY19kYXRhLCBjdEROQS5TdXJ2ZWlsbGFuY2UgJWluJSBjKCJORUdBVElWRSIsICJQT1NJVElWRSIpKQpjaXJjX2RhdGEkU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRTdGFnZSwgbGV2ZWxzPWMoIklJIiwgIklJSSIpKQpwb3NpdGl2ZV9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIiwgYnk9bGlzdChjaXJjX2RhdGEkU3RhZ2UpLCBGVU49c3VtKQp0b3RhbF9jb3VudHNfYnlfc3RhZ2UgPC0gYWdncmVnYXRlKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGJ5PWxpc3QoY2lyY19kYXRhJFN0YWdlKSwgRlVOPWxlbmd0aCkKY29tYmluZWRfZGF0YSA8LSBkYXRhLmZyYW1lKAogIFN0YWdlID0gdG90YWxfY291bnRzX2J5X3N0YWdlJEdyb3VwLjEsCiAgVG90YWxfQ291bnQgPSB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCwKICBQb3NpdGl2ZV9Db3VudCA9IHBvc2l0aXZlX2NvdW50c19ieV9zdGFnZSR4LAogIFJhdGUgPSAocG9zaXRpdmVfY291bnRzX2J5X3N0YWdlJHggLyB0b3RhbF9jb3VudHNfYnlfc3RhZ2UkeCkgKiAxMDAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCikKY29tYmluZWRfZGF0YSRSYXRlIDwtIHNwcmludGYoIiUuMmYlJSIsIGNvbWJpbmVkX2RhdGEkUmF0ZSkKb3ZlcmFsbF90b3RhbF9jb3VudCA8LSBucm93KGNpcmNfZGF0YSkKb3ZlcmFsbF9wb3NpdGl2ZV9jb3VudCA8LSBucm93KGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIsXSkKb3ZlcmFsbF9wb3NpdGl2aXR5X3JhdGUgPC0gKG92ZXJhbGxfcG9zaXRpdmVfY291bnQgLyBvdmVyYWxsX3RvdGFsX2NvdW50KSAqIDEwMCAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKb3ZlcmFsbF9yb3cgPC0gZGF0YS5mcmFtZSgKICBTdGFnZSA9ICJPdmVyYWxsIiwKICBUb3RhbF9Db3VudCA9IG92ZXJhbGxfdG90YWxfY291bnQsCiAgUG9zaXRpdmVfQ291bnQgPSBvdmVyYWxsX3Bvc2l0aXZlX2NvdW50LAogIFJhdGUgPSBzcHJpbnRmKCIlLjJmJSUiLCBvdmVyYWxsX3Bvc2l0aXZpdHlfcmF0ZSkKKQpjb21iaW5lZF9kYXRhIDwtIHJiaW5kKGNvbWJpbmVkX2RhdGEsIG92ZXJhbGxfcm93KQpwcmludChjb21iaW5lZF9kYXRhKQpgYGAKCgoKI2N0RE5BIE1SRCBEZXRlY3Rpb24gcmF0ZSBTdGFnZSBJSSB2cyBJSUkKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRTdGFnZV9Hcm91cGVkIDwtIGZhY3RvcihpZmVsc2UoY2lyY19kYXRhJFN0YWdlICVpbiUgYygiSUkiLCAiSUkiKSwgIklJIiwgIklJSSIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkU3RhZ2VfR3JvdXBlZCwgY2lyY19kYXRhJGN0RE5BLk1SRCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmBgYAoKI2N0RE5BIFN1cnZlaWxsYW5jZSBEZXRlY3Rpb24gcmF0ZSBTdGFnZSBJSSB2cyBJSUkKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGxldmVscyA9IGMoIk5FR0FUSVZFIiwgIlBPU0lUSVZFIikpCmNpcmNfZGF0YSRTdGFnZV9Hcm91cGVkIDwtIGZhY3RvcihpZmVsc2UoY2lyY19kYXRhJFN0YWdlICVpbiUgYygiSUkiLCAiSUkiKSwgIklJIiwgIklJSSIpKQpjb250aW5nZW5jeV90YWJsZSA8LSB0YWJsZShjaXJjX2RhdGEkU3RhZ2VfR3JvdXBlZCwgY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNvbnRpbmdlbmN5X3RhYmxlKQpwcmludChjaGlfc3F1YXJlX3Rlc3QpCmBgYAoKI2N0RE5BIHRpbWVwb2ludHMgY2FkZW5jZSBhdCB0aGUgTVJEIFdpbmRvdwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKSAKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCgpjaXJjX2RhdGEkTVJEX1RpbWVfd2Vla3MgPC0gY2lyY19kYXRhJGN0RE5BLk1SRC5UaW1lIC8gNwoKIyBQbG90IHRoZSBoaXN0b2dyYW0KaGlzdChjaXJjX2RhdGEkTVJEX1RpbWVfd2Vla3MsCiAgICAgY29sID0gJ2dyYXknLAogICAgIG1haW4gPSAnU3VyZ2VyeSB0byBmaXJzdCBjdEROQSB0ZXN0aW5nIGF0IE1SRCB3aW5kb3cnLAogICAgIHhsYWIgPSAnV2Vla3MgZnJvbSBzdXJnZXJ5IHRvIGZpcnN0IGN0RE5BIHRlc3QgYXQgTVJEIHdpbmRvdycsCiAgICAgeWxhYiA9ICdjdEROQSBTYW1wbGVzJywKICAgICB5bGltID0gYygwLCAxMjApLAogICAgIHhsaW0gPSBjKDAsIDEwKSwKICAgICBicmVha3MgPSBzZXEoMCwgMjQsIDEpLAogICAgIHhheHAgPSBjKDAsIDI0LCAyNCkpCmBgYAoKI0RGUyBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdyAtIEFsbCBzdGFnZXMgTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5NUkQsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLk1SRCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBNUkQgd2luZG93IHwgQWxsIHN0YWdlcyIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDE4LCAyNCkpCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5NUkQsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyLCAxOCwgYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYygxMiwgMTgsIDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgoKCiNNdWx0aXZhcmlhdGUgY294IHJlZ3Jlc3Npb24gYXQgTVJEIFdpbmRvdyBmb3IgREZTIC0gQWxsIHN0YWdlcyBMYW5kbWFyayBNUkQgdGltZXBvaW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJExWSSA8LSBmYWN0b3IoY2lyY19kYXRhJExWSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSkKY2lyY19kYXRhJFBOSSA8LSBmYWN0b3IoY2lyY19kYXRhJFBOSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSkKY2lyY19kYXRhJEdyYWRlIDwtIGZhY3RvcihjaXJjX2RhdGEkR3JhZGUsIGxldmVscyA9IGMoIkcxIiwgIkcyL0czIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCArIEdlbmRlciArIEFnZS5Hcm91cCArIEVDT0cgKyBwVCArIHBOICsgTFZJICsgUE5JICsgR3JhZGUgKyBSQVMsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCwgZGF0YSA9IGNpcmNfZGF0YSwgbWFpbiA9ICJNdWx0aXZhcmlhdGUgUmVncmVzc2lvbiBNb2RlbCBmb3IgREZTIC0gQWxsIFN0YWdlcyIsIHJlZkxhYmVsID0gIlJlZmVyZW5jZSBHcm91cCIpCnRlc3QucGggPC0gY294LnpwaChjb3hfZml0KQpgYGAKCgojREZTIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93IC0gU3RhZ2UgSUkgTGFuZG1hcmsgTVJEIHRpbWVwb2ludApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbIShjaXJjX2RhdGEkU3RhZ2UgJWluJSBjKCJJSUkiKSksXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCl+Y3RETkEuTVJELCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5NUkQpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpIApnZ3N1cnZwbG90KEtNX2N1cnZlLCBkYXRhID0gY2lyY19kYXRhLCBwdmFsID0gRkFMU0UsIGNvbmYuaW50ID0gRkFMU0UsIHJpc2sudGFibGUgPSBUUlVFLCBicmVhay50aW1lLmJ5PTYsIHBhbGV0dGU9YygiYmx1ZSIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIHdpbmRvdyB8IFN0YWdlIElJIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQpKQpjaXJjX2RhdGEkY3RETkEuTVJEIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuTVJELCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuTVJELCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiBhbmQgMjQgbW9udGhzCmRmc190aW1lcyA8LSBjKDEyLCAyNCkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKYGBgCgojREZTIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93IC0gU3RhZ2UgSUlJIExhbmRtYXJrIE1SRCB0aW1lcG9pbnQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJEVsaWdpYmxlPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVshKGNpcmNfZGF0YSRTdGFnZSAlaW4lIGMoIklJIikpLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLk1SRCwgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuTVJEKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5NUkQsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCB3aW5kb3cgfCBTdGFnZSBJSUkiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0LCAzMCkpCmNpcmNfZGF0YSRjdEROQS5NUkQgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5NUkQsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5NUkQsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKQpzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDI0IGFuZCAzMCBtb250aHMKZGZzX3RpbWVzIDwtIGMoMjQsIDMwKQpjaXJjX2RhdGEgPC0gbmEub21pdChjaXJjX2RhdGFbLCBjKCJjdEROQS5NUkQiLCAiREZTLk1SRC5tb250aHMiLCAiREZTLkV2ZW50IildKQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuTVJEID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgoKCgoKI0RGUyBieSBBQ1QgdHJlYXRtZW50IGluIE1SRCBuZWdhdGl2ZSAtIFN0YWdlIElJL0lJSQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09Ik5FR0FUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5BQ1QsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KEFDVCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoInJlZCIsImJsdWUiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBOZWdhdGl2ZSBBQ1QgdnMgT2JzZXJ2YXRpb24gfCBTdGFnZSBJSS9JSUkiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJPYnNlcnZhdGlvbiIsICJBQ1QiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygyNCkpCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscz1jKCJUUlVFIiwiRkFMU0UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMjQKZGZzX3RpbWVzIDwtIGMoMjQpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIlRSVUUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkQUNUID09ICJUUlVFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJEFDVCA9PSAiVFJVRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRBQ1QgPT0gIkZBTFNFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCiNBZGp1c3RlZCBIUiAiQUNUIHZzIG5vIEFDVCIgLSBOb24gQUNUIGFzIHJlZmVyZW5jZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEPT0iTkVHQVRJVkUiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkQUNUIDwtIGZhY3RvcihjaXJjX2RhdGEkQUNULCBsZXZlbHM9YygiRkFMU0UiLCJUUlVFIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAi4omlNzAiKSkKY2lyY19kYXRhJEdlbmRlciA8LSBmYWN0b3IoY2lyY19kYXRhJEdlbmRlciwgbGV2ZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkKY2lyY19kYXRhJFN0YWdlIDwtIGZhY3RvcihjaXJjX2RhdGEkU3RhZ2UsIGxldmVscyA9IGMoIklJIiwgIklJSSIpKQpjaXJjX2RhdGEkRUNPRyA8LSBmYWN0b3IoY2lyY19kYXRhJEVDT0csIGxldmVscz1jKCIwIiwiMSIpKQpzdXJ2X29iamVjdCA8LSBTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KSAKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCArIEdlbmRlciArIEFnZS5Hcm91cCArIFN0YWdlICsgRUNPRywgZGF0YT1jaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKYGBgCgoKI0RGUyBieSBBQ1QgdHJlYXRtZW50IGluIE1SRCBwb3NpdGl2ZSAtIFN0YWdlIElJL0lJSQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09IlBPU0lUSVZFIixdCmNpcmNfZGF0YSRERlMubW9udGhzPWNpcmNfZGF0YSRERlMubW9udGhzLTIKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5BQ1QsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KEFDVCkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBBQ1QsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoInJlZCIsImJsdWUiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIE1SRCBQb3NpdGl2ZSBBQ1QgdnMgT2JzZXJ2YXRpb24gfCBTdGFnZSBJSS9JSUkiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJPYnNlcnZhdGlvbiIsICJBQ1QiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYyg2LCAyNCkpCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscz1jKCJUUlVFIiwiRkFMU0UiKSkKY294X2ZpdCA8LSBjb3hwaChzdXJ2X29iamVjdCB+IEFDVCwgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0FkanVzdGVkIEhSICJBQ1QgdnMgbm8gQUNUIiAtIE5vbiBBQ1QgYXMgcmVmZXJlbmNlCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJQT1NJVElWRSIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRBQ1QgPC0gZmFjdG9yKGNpcmNfZGF0YSRBQ1QsIGxldmVscz1jKCJGQUxTRSIsIlRSVUUiKSkKY2lyY19kYXRhJEFnZS5Hcm91cCA8LSBmYWN0b3IoY2lyY19kYXRhJEFnZS5Hcm91cCwgbGV2ZWxzID0gYygiMSIsICIyIiksIGxhYmVscyA9IGMoIjw3MCIsICLiiaU3MCIpKQpjaXJjX2RhdGEkR2VuZGVyIDwtIGZhY3RvcihjaXJjX2RhdGEkR2VuZGVyLCBsZXZlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKQpjaXJjX2RhdGEkU3RhZ2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRTdGFnZSwgbGV2ZWxzID0gYygiSUkiLCAiSUlJIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzPWMoIjAiLCIxIikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gQUNUICsgR2VuZGVyICsgQWdlLkdyb3VwICsgU3RhZ2UgKyBFQ09HLCBkYXRhPWNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojREZTIGJ5IGN0RE5BIGF0IDMgbW9udGhzIC0gQWxsIHN0YWdlcyBMYW5kbWFyayAzIG1vbnRocyB0aW1lcG9pbnQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLjNtb250aHMhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLjNtby5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy4zbW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLjNtb250aHMsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLjNtb250aHMpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjNtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLjNtb250aHMsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIDMgbW9udGhzIHwgQWxsIHN0YWdlcyIsIHlsYWI9ICJEaXNlYXNlLUZyZWUgU3Vydml2YWwiLCB4bGFiPSJUaW1lIGZyb20gTGFuZG1hcmsgVGltZSBwb2ludCAoTW9udGhzKSIsIGxlZ2VuZC5sYWJzPWMoImN0RE5BIE5lZ2F0aXZlIiwgImN0RE5BIFBvc2l0aXZlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLjNtb250aHMgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS4zbW9udGhzLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuM21vbnRocywgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMTIgYW5kIDI0IG1vbnRocwpkZnNfdGltZXMgPC0gYygxMiwgMjQpCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS4zbW9udGhzID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLjNtby5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS4zbW9udGhzID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLjNtby5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS4zbW9udGhzID09ICJORUdBVElWRSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuM21vbnRocyA9PSAiUE9TSVRJVkUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuM21vbnRocyA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLjNtb250aHMgPT0gIlBPU0lUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuM21vLm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCmBgYAoKCgoKI0RGUyBieSBjdEROQSBhdCA2IG1vbnRocyAtIEFsbCBzdGFnZXMgTGFuZG1hcmsgNiBtb250aHMgdGltZXBvaW50CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS42bW9udGhzIT0iIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy42bW8ubW9udGhzPj0wLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS42bW9udGhzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS42bW9udGhzKSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbCA9IG4oKSwKICAgIEV2ZW50cyA9IHN1bShERlMuRXZlbnQpLAogICAgRnJhY3Rpb24gPSBFdmVudHMgLyBuKCksCiAgICBQZXJjZW50YWdlID0gKEV2ZW50cyAvIG4oKSkgKiAxMDAKICApCnByaW50KGV2ZW50X3N1bW1hcnkpCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy42bW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS42bW9udGhzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSA2IG1vbnRocyB8IEFsbCBzdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJjdEROQSBOZWdhdGl2ZSIsICJjdEROQSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDYsIDI0KSkKY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS42bW9udGhzLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuNm1vbnRocywgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpCnN1bW1hcnkoY294X2ZpdCkKY294X2ZpdF9zdW1tYXJ5IDwtIHN1bW1hcnkoY294X2ZpdCkKCiMgRXh0cmFjdCB2YWx1ZXMgZm9yIEhSLCA5NSUgQ0ksIGFuZCBwLXZhbHVlCkhSIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbMl0KbG93ZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzNdCnVwcGVyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFs0XQpwX3ZhbHVlIDwtIGNveF9maXRfc3VtbWFyeSRjb2VmZmljaWVudHNbNV0KbGFiZWxfdGV4dCA8LSBwYXN0ZTAoIkhSID0gIiwgcm91bmQoSFIsIDIpLCAiICgiLCByb3VuZChsb3dlcl9DSSwgMiksICItIiwgcm91bmQodXBwZXJfQ0ksIDIpLCAiKTsgcCA9ICIsIHJvdW5kKHBfdmFsdWUsIDMpKQpwcmludChsYWJlbF90ZXh0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgNiBhbmQgMjQgbW9udGhzCmRmc190aW1lcyA8LSBjKDYsIDI0KQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy42bW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy42bW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgbmVnX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLjZtb250aHMgPT0gIk5FR0FUSVZFIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS42bW9udGhzID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLjZtby5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgoKCiNERlMgYnkgY3RETkEgQ2xlYXJhbmNlIEFDVC10cmVhdGVkIGF0IDMgbW9udGhzIC0gYWxsIHN0YWdlcwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdIApjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRBQ1Q9PVRSVUUsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuM21vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuM21vbnRocyA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuM21vLm1vbnRocz49MCxdCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy4zbW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5EeW5hbWljcykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuM21vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIENsZWFyYW5jZSBmcm9tIE1SRCB0byAzIG1vbnRocyBBQ1QtdHJlYXRlZCB8IEFsbCBTdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcywgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpIApzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyIGFuZCAyNCBtb250aHMKZGZzX3RpbWVzIDwtIGMoMTIpCmNpcmNfZGF0YSA8LSBuYS5vbWl0KGNpcmNfZGF0YVssIGMoImN0RE5BLkR5bmFtaWNzIiwgIkRGUy4zbW8ubW9udGhzIiwgIkRGUy5FdmVudCIpXSkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJDbGVhcmFuY2UiICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IEZBTFNFKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJObyBDbGVhcmFuY2UiICYgY2lyY19kYXRhJERGUy4zbW8ubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IEZBTFNFKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJDbGVhcmFuY2UiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJObyBDbGVhcmFuY2UiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkNsZWFyYW5jZSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IFRSVUUgJiBjaXJjX2RhdGEkREZTLjNtby5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIk5vIENsZWFyYW5jZSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IFRSVUUgJiBjaXJjX2RhdGEkREZTLjNtby5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQpgYGAKCgojREZTIGJ5IGN0RE5BIENsZWFyYW5jZSBBQ1QtdHJlYXRlZCBhdCA2IG1vbnRocyAtIGFsbCBzdGFnZXMKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRBQ1Q9PVRSVUUsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiIH4gMgogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuNm1vLm1vbnRocz49MCxdCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy42bW8ubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5EeW5hbWljcykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIENsZWFyYW5jZSBmcm9tIE1SRCB0byA2IG1vbnRocyBBQ1QtdHJlYXRlZCB8IEFsbCBTdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIiksIGxlZ2VuZC50aXRsZT0iIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIpLCBsYWJlbHMgPSBjKCJDbGVhcmFuY2UiLCAiTm8gQ2xlYXJhbmNlIikpCmNveF9maXQgPC0gY294cGgoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcywgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LGRhdGEgPSBjaXJjX2RhdGEpIApzdW1tYXJ5KGNveF9maXQpCmNveF9maXRfc3VtbWFyeSA8LSBzdW1tYXJ5KGNveF9maXQpCgojIEV4dHJhY3QgdmFsdWVzIGZvciBIUiwgOTUlIENJLCBhbmQgcC12YWx1ZQpIUiA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzJdCmxvd2VyX0NJIDwtIGNveF9maXRfc3VtbWFyeSRjb25mLmludFszXQp1cHBlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbNF0KcF92YWx1ZSA8LSBjb3hfZml0X3N1bW1hcnkkY29lZmZpY2llbnRzWzVdCmxhYmVsX3RleHQgPC0gcGFzdGUwKCJIUiA9ICIsIHJvdW5kKEhSLCAyKSwgIiAoIiwgcm91bmQobG93ZXJfQ0ksIDIpLCAiLSIsIHJvdW5kKHVwcGVyX0NJLCAyKSwgIik7IHAgPSAiLCByb3VuZChwX3ZhbHVlLCAzKSkKcHJpbnQobGFiZWxfdGV4dCkKYGBgCgoKI1BlcmNlbnRhZ2VzIG9mIE1SRCBuZWdhdGl2ZSB3aXRoIG1vbGVjdWxhciByZWN1cnJlbmNlIChyZXR1cm5lZCBwb3NpdGl2ZSkgcG9zdC1NUkQKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCAhPSAiIiAmIGNpcmNfZGF0YSRMZWFkLlRpbWUgPj0gMCwgXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQ9PSJORUdBVElWRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRQb3N0TVJEUG9zLkV2ZW50PT0iVFJVRSIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCiMgQ29udmVydCBkYXlzIHRvIG1vbnRocwpjaXJjX2RhdGEkUG9zdE1SRFBvcy5tb250aHMgPC0gY2lyY19kYXRhJFBvc3RNUkRQb3MvMzAuNDM3CgojIERlZmluZSB0aGUgaW50ZXJ2YWxzOiAwLTYsIDYtOSwgOS0xMiwgMTItMTUsIDE1LTE4LCAxOC0yMSwgMjEtMjQsID4yNCBtb250aHMKYnJlYWtzIDwtIGMoMCwgNiwgOSwgMTIsIDE1LCAxOCwgMjEsIDI0LCA0OCkKbGFiZWxzIDwtIGMoIjAtNm0iLCAiNi05bSIsICI5LTEybSIsICIxMi0xNW0iLCAiMTUtMThtIiwgIjE4LTIxbSIsICIyMS0yNG0iLCAiPjI0bSIpCgojIENhdGVnb3JpemUgcF9kcmVsUmV0dXJuZWRfbW9udGhzIGludG8gaW50ZXJ2YWxzCmNpcmNfZGF0YSRwX2RyZWxSZXR1cm5lZF9pbnRlcnZhbHMgPC0gY3V0KGNpcmNfZGF0YSRQb3N0TVJEUG9zLm1vbnRocywgYnJlYWtzID0gYnJlYWtzLCBsYWJlbHMgPSBsYWJlbHMsIHJpZ2h0ID0gRkFMU0UpCgojIEV4YW1pbmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgaW50ZXJ2YWxzCnRhYmxlKGNpcmNfZGF0YSRwX2RyZWxSZXR1cm5lZF9pbnRlcnZhbHMpCgojIEdldCB0aGUgY291bnRzIGZvciBlYWNoIGludGVydmFsCmludGVydmFsX2NvdW50cyA8LSB0YWJsZShjaXJjX2RhdGEkcF9kcmVsUmV0dXJuZWRfaW50ZXJ2YWxzKQoKIyBDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2VzCmludGVydmFsX3BlcmNlbnRhZ2VzIDwtIDEwMCAqIGludGVydmFsX2NvdW50cyAvIHN1bShpbnRlcnZhbF9jb3VudHMpCgojIENvbWJpbmUgdGhlIGNvdW50cyBhbmQgcGVyY2VudGFnZXMgZm9yIGEgY2xlYXJlciBvdmVydmlldwppbnRlcnZhbF9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoQ291bnRzID0gaW50ZXJ2YWxfY291bnRzLCBQZXJjZW50YWdlcyA9IGludGVydmFsX3BlcmNlbnRhZ2VzKQoKIyBDYWxjdWxhdGUgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMKdG90YWxfb2JzZXJ2YXRpb25zIDwtIHN1bShpbnRlcnZhbF9jb3VudHMpCgojIEFkZCB0aGUgdG90YWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyB0byB0aGUgc3VtbWFyeQppbnRlcnZhbF9zdW1tYXJ5JFRvdGFsT2JzZXJ2YXRpb25zIDwtIGMocmVwKE5BLCBsZW5ndGgoaW50ZXJ2YWxfY291bnRzKS0xKSwgdG90YWxfb2JzZXJ2YXRpb25zKQoKIyBQcmludCB0aGUgc3VtbWFyeSB3aXRoIHRvdGFsIG9ic2VydmF0aW9ucwpwcmludChpbnRlcnZhbF9zdW1tYXJ5KQoKIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwZXJjZW50YWdlcwpjdW11bGF0aXZlX3BlcmNlbnRhZ2VzIDwtIGN1bXN1bShpbnRlcnZhbF9wZXJjZW50YWdlcykKCiMgQ29tYmluZSB0aGUgY291bnRzLCBwZXJjZW50YWdlcywgYW5kIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMgZm9yIGEgY2xlYXJlciBvdmVydmlldwppbnRlcnZhbF9zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoQ291bnRzID0gaW50ZXJ2YWxfY291bnRzLCBQZXJjZW50YWdlcyA9IGludGVydmFsX3BlcmNlbnRhZ2VzLCBDdW11bGF0aXZlUGVyY2VudGFnZXMgPSBjdW11bGF0aXZlX3BlcmNlbnRhZ2VzLCBUb3RhbE9ic2VydmF0aW9ucyA9IGMocmVwKE5BLCBsZW5ndGgoaW50ZXJ2YWxfY291bnRzKS0xKSwgdG90YWxfb2JzZXJ2YXRpb25zKSkKCmJwIDwtIGJhcnBsb3QoaW50ZXJ2YWxfcGVyY2VudGFnZXMsIAogICAgICAgICAgICAgIG1haW49Ik1vbGVjdWxhciBSZWN1cnJlbmNlIHBvc3QtTVJEIGluIE1SRCBuZWdhdGl2ZSBwYXRpZW50cyIsIAogICAgICAgICAgICAgIHhsYWI9Ik1vbnRocyBJbnRlcnZhbCBmcm9tIFN1cmdlcnkiLCAKICAgICAgICAgICAgICB5bGFiPSJQYXRpZW50cyAlIGNvbnZlcnRlZCBwb3NpdGl2ZSIsIAogICAgICAgICAgICAgIGNvbD0ibGlnaHRibHVlIiwKICAgICAgICAgICAgICB5bGltPWMoMCwgMTAwKSkKCiMgQWRkIHRoZSBjdW11bGF0aXZlIHBlcmNlbnRhZ2VzIHRvIHRoZSBwbG90CnBvaW50cyhicCwgY3VtdWxhdGl2ZV9wZXJjZW50YWdlcywgdHlwZT0ibyIsIHBjaD0yMiwgY29sPSJyZWQiLCBjZXg9MS41KQpwcmludChpbnRlcnZhbF9zdW1tYXJ5KQpgYGAKCgoKCiNERlMgYnkgY3RETkEgTVJEIHBvc2l0aXZlIHZzIGN0RE5BIG5lZ2F0aXZlIHdpdGggbW9sZWN1bGFyIHJlY3VycmVuY2UgYXQgU3VydmVpbGxhbmNlIC0gMyBncm91cHMKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuU3VydmVpbGxhbmNlPT0iTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuU3VydmVpbGxhbmNlPT0iUE9TSVRJVkUiIH4gMiwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiIH4gMwogICkpCgpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCnN1cnZmaXQoU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpfmN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhKQpldmVudF9zdW1tYXJ5IDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShjdEROQS5EeW5hbWljcykgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpLTV9jdXJ2ZSA8LSBzdXJ2Zml0KHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJncmVlbiIsInJlZCIpLCB0aXRsZT0iREZTIC0gY3RETkEgTVJEIFBvcyB2cyBOZWcgd2l0aCBNb2xlY3VsYXIgUmVjdXJyZW5jZSBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93IiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiQWxsLXRpbWUgbmVnYXRpdmUiLCJNb2xlY3VsYXIgUmVjdXJyZW5jZSIsICJjdEROQSBNUkQgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQpKQpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgbGV2ZWxzPWMoIjEiLCIyIiwiMyIpLCBsYWJlbHMgPSBjKCJBbGwtdGltZSBuZWdhdGl2ZSIsIk1vbGVjdWxhciBSZWN1cnJlbmNlIiwgImN0RE5BIE1SRCBQb3NpdGl2ZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQoKI0Zpc2hlciB0ZXN0IGZvciBERlMgcGVyY2VudGFnZXMgYXQgMTIgYW5kIDI0IG1vbnRocyAtIEFsbCB0aW1lIG5lZ2F0aXZlIHZzIE1vbGVjdWxhciBSZWN1cnJlbmNlCmRmc190aW1lcyA8LSBjKDEyLCAyNCkKY2lyY19kYXRhIDwtIG5hLm9taXQoY2lyY19kYXRhWywgYygiY3RETkEuRHluYW1pY3MiLCAiREZTLk1SRC5tb250aHMiLCAiREZTLkV2ZW50IildKQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJNb2xlY3VsYXIgUmVjdXJyZW5jZSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQWxsLXRpbWUgbmVnYXRpdmUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJNb2xlY3VsYXIgUmVjdXJyZW5jZSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQWxsLXRpbWUgbmVnYXRpdmUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJNb2xlY3VsYXIgUmVjdXJyZW5jZSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPCB0aW1lKQogIAogIHN1cnZfbWF0cml4IDwtIG1hdHJpeChjKG5lZ19zdXJ2LCBwb3Nfc3VydiwgbmVnX3RvdGFsIC0gbmVnX3N1cnYsIHBvc190b3RhbCAtIHBvc19zdXJ2KSwgbnJvdyA9IDIpCiAgdGVzdF9yZXN1bHQgPC0gZmlzaGVyLnRlc3Qoc3Vydl9tYXRyaXgpCiAgcmV0dXJuKHRlc3RfcmVzdWx0JHAudmFsdWUpCn0pCm5hbWVzKHBfdmFsdWVzKSA8LSBwYXN0ZTAoInAtdmFsdWUgYXQgIiwgZGZzX3RpbWVzLCAiIG1vbnRocyIpCnByaW50KHBfdmFsdWVzKQoKI1JlcGVhdCBhbmFseXNpcyB0byBydW4gRmlzaGVyIHRlc3QgZm9yIEFsbCB0aW1lIG5lZ2F0aXZlIHZzIGN0RE5BIFBvc2l0aXZlCnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQoKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIE5BICNmaXJzdCB3ZSBjcmVhdGUgdGhlIHZhcmlhYmxlIGZvciB0aGUgY3RETkEgJiBOQUMgY29tYmluYXRpb24sIGFuZCB3ZSBhc3NpZ24gdmFsdWVzCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGEgJT4lCiAgbXV0YXRlKGN0RE5BLkR5bmFtaWNzID0gY2FzZV93aGVuKAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJORUdBVElWRSIgfiAxLAogICAgY3RETkEuTVJEID09ICJORUdBVElWRSIgJiBjdEROQS5TdXJ2ZWlsbGFuY2U9PSJQT1NJVElWRSIgfiAyLAogICAgY3RETkEuTVJEID09ICJQT1NJVElWRSIgfiAzCiAgKSkKCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5NUkQubW9udGhzPj0wLF0KCnN1cnZfb2JqZWN0IDwtU3Vydih0aW1lID0gY2lyY19kYXRhJERGUy5NUkQubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSxjb25mLmludD0wLjk1LGNvbmYudHlwZT0ibG9nLWxvZyIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDEyLCAyNCkpCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzLCBsZXZlbHM9YygiMSIsIjIiLCIzIiksIGxhYmVscyA9IGMoIkFsbC10aW1lIG5lZ2F0aXZlIiwiTW9sZWN1bGFyIFJlY3VycmVuY2UiLCAiY3RETkEgTVJEIFBvc2l0aXZlIikpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiBhbmQgMjQgbW9udGhzIC0gQWxsIHRpbWUgbmVnYXRpdmUgdnMgY3RETkEgUG9zaXRpdmUKZGZzX3RpbWVzIDwtIGMoMTIsIDI0KQpjaXJjX2RhdGEgPC0gbmEub21pdChjaXJjX2RhdGFbLCBjKCJjdEROQS5EeW5hbWljcyIsICJERlMuTVJELm1vbnRocyIsICJERlMuRXZlbnQiKV0pCnBfdmFsdWVzIDwtIHNhcHBseShkZnNfdGltZXMsIGZ1bmN0aW9uKHRpbWUpIHsKICBuZWdfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQWxsLXRpbWUgbmVnYXRpdmUiICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzID49IHRpbWUgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDApCiAgcG9zX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gImN0RE5BIE1SRCBQb3NpdGl2ZSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiQWxsLXRpbWUgbmVnYXRpdmUiKQogIHBvc190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJjdEROQSBNUkQgUG9zaXRpdmUiKQogIAogIG5lZ19zdXJ2IDwtIG5lZ190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gIkFsbC10aW1lIG5lZ2F0aXZlIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgcG9zX3N1cnYgPC0gcG9zX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiY3RETkEgTVJEIFBvc2l0aXZlIiAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMSAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCgojUmVwZWF0IGFuYWx5c2lzIHRvIHJ1biBGaXNoZXIgdGVzdCBmb3IgTW9sZWN1bGFyIFJlY3VycmVuY2UgdnMgY3RETkEgUG9zaXRpdmUKcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkY3RETkEuTVJEIT0iIixdCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09Ik5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09IlBPU0lUSVZFIiB+IDIsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiB+IDMKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQoKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikKc3VtbWFyeShLTV9jdXJ2ZSwgdGltZXM9IGMoMTIsIDI0KSkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIsIjMiKSwgbGFiZWxzID0gYygiQWxsLXRpbWUgbmVnYXRpdmUiLCJNb2xlY3VsYXIgUmVjdXJyZW5jZSIsICJjdEROQSBNUkQgUG9zaXRpdmUiKSkKCiNGaXNoZXIgdGVzdCBmb3IgREZTIHBlcmNlbnRhZ2VzIGF0IDEyIGFuZCAyNCBtb250aHMgLSBNb2xlY3VsYXIgUmVjdXJyZW5jZSB2cyBjdEROQSBQb3NpdGl2ZQpkZnNfdGltZXMgPC0gYygxMiwgMjQpCmNpcmNfZGF0YSA8LSBuYS5vbWl0KGNpcmNfZGF0YVssIGMoImN0RE5BLkR5bmFtaWNzIiwgIkRGUy5NUkQubW9udGhzIiwgIkRGUy5FdmVudCIpXSkKcF92YWx1ZXMgPC0gc2FwcGx5KGRmc190aW1lcywgZnVuY3Rpb24odGltZSkgewogIG5lZ19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJNb2xlY3VsYXIgUmVjdXJyZW5jZSIgJiBjaXJjX2RhdGEkREZTLk1SRC5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBwb3NfY291bnQgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiY3RETkEgTVJEIFBvc2l0aXZlIiAmIGNpcmNfZGF0YSRERlMuTVJELm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIG5lZ190b3RhbCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJNb2xlY3VsYXIgUmVjdXJyZW5jZSIpCiAgcG9zX3RvdGFsIDwtIHN1bShjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPT0gImN0RE5BIE1SRCBQb3NpdGl2ZSIpCiAgCiAgbmVnX3N1cnYgPC0gbmVnX3RvdGFsIC0gc3VtKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA9PSAiTW9sZWN1bGFyIFJlY3VycmVuY2UiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICBwb3Nfc3VydiA8LSBwb3NfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzID09ICJjdEROQSBNUkQgUG9zaXRpdmUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5NUkQubW9udGhzIDwgdGltZSkKICAKICBzdXJ2X21hdHJpeCA8LSBtYXRyaXgoYyhuZWdfc3VydiwgcG9zX3N1cnYsIG5lZ190b3RhbCAtIG5lZ19zdXJ2LCBwb3NfdG90YWwgLSBwb3Nfc3VydiksIG5yb3cgPSAyKQogIHRlc3RfcmVzdWx0IDwtIGZpc2hlci50ZXN0KHN1cnZfbWF0cml4KQogIHJldHVybih0ZXN0X3Jlc3VsdCRwLnZhbHVlKQp9KQpuYW1lcyhwX3ZhbHVlcykgPC0gcGFzdGUwKCJwLXZhbHVlIGF0ICIsIGRmc190aW1lcywgIiBtb250aHMiKQpwcmludChwX3ZhbHVlcykKCiNSZXBlYXQgdG8gY29tcGFyZSBIUnMgZm9yIE1vbGVjdWxhciBSZWN1cnJlbmNlIHZzIGN0RE5BIE1SRCBwb3NpdGl2ZQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhZGYgPC0gYXMuZGF0YS5mcmFtZShjaXJjX2RhdGEpCgpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gTkEgI2ZpcnN0IHdlIGNyZWF0ZSB0aGUgdmFyaWFibGUgZm9yIHRoZSBjdEROQSAmIE5BQyBjb21iaW5hdGlvbiwgYW5kIHdlIGFzc2lnbiB2YWx1ZXMKY2lyY19kYXRhIDwtIGNpcmNfZGF0YSAlPiUKICBtdXRhdGUoY3RETkEuRHluYW1pY3MgPSBjYXNlX3doZW4oCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09Ik5FR0FUSVZFIiB+IDEsCiAgICBjdEROQS5NUkQgPT0gIk5FR0FUSVZFIiAmIGN0RE5BLlN1cnZlaWxsYW5jZT09IlBPU0lUSVZFIiB+IDIsCiAgICBjdEROQS5NUkQgPT0gIlBPU0lUSVZFIiB+IDMKICApKQoKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLk1SRC5tb250aHM+PTAsXQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuTVJELm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KQpjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5EeW5hbWljcywgbGV2ZWxzPWMoIjIiLCIzIiksIGxhYmVscyA9IGMoIk1vbGVjdWxhciBSZWN1cnJlbmNlIiwgImN0RE5BIE1SRCBQb3NpdGl2ZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCmBgYAoKI0RGUyBieSBjdEROQSBhdCB0aGUgU3VydmVpbGxhbmNlIFdpbmRvdyAtIEFsbCBzdGFnZXMgTGFuZG1hcmsgMTAgd2Vla3MKYGBge3J9CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSE9IiIsXQpjaXJjX2RhdGEkREZTLm1vbnRocz1jaXJjX2RhdGEkREZTLm1vbnRocy0yLjUKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLm1vbnRocz49MCxdCmNpcmNfZGF0YWRmIDwtIGFzLmRhdGEuZnJhbWUoY2lyY19kYXRhKQoKc3VydmZpdChTdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEpCmV2ZW50X3N1bW1hcnkgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KGN0RE5BLlN1cnZlaWxsYW5jZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgVG90YWwgPSBuKCksCiAgICBFdmVudHMgPSBzdW0oREZTLkV2ZW50KSwKICAgIEZyYWN0aW9uID0gRXZlbnRzIC8gbigpLAogICAgUGVyY2VudGFnZSA9IChFdmVudHMgLyBuKCkpICogMTAwCiAgKQpwcmludChldmVudF9zdW1tYXJ5KQpzdXJ2X29iamVjdCA8LVN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpCktNX2N1cnZlIDwtIHN1cnZmaXQoc3Vydl9vYmplY3QgfiBjdEROQS5TdXJ2ZWlsbGFuY2UsIGRhdGEgPSBjaXJjX2RhdGEsY29uZi5pbnQ9MC45NSxjb25mLnR5cGU9ImxvZy1sb2ciKSAKZ2dzdXJ2cGxvdChLTV9jdXJ2ZSwgZGF0YSA9IGNpcmNfZGF0YSwgcHZhbCA9IEZBTFNFLCBjb25mLmludCA9IEZBTFNFLCByaXNrLnRhYmxlID0gVFJVRSwgYnJlYWsudGltZS5ieT02LCBwYWxldHRlPWMoImJsdWUiLCJyZWQiKSwgdGl0bGU9IkRGUyAtIGN0RE5BIFN1cnZlaWxsYW5jZSB3aW5kb3cgfCBBbGwgc3RhZ2VzIiwgeWxhYj0gIkRpc2Vhc2UtRnJlZSBTdXJ2aXZhbCIsIHhsYWI9IlRpbWUgZnJvbSBMYW5kbWFyayBUaW1lIHBvaW50IChNb250aHMpIiwgbGVnZW5kLmxhYnM9YygiY3RETkEgTmVnYXRpdmUiLCAiY3RETkEgUG9zaXRpdmUiKSwgbGVnZW5kLnRpdGxlPSIiKQpzdW1tYXJ5KEtNX2N1cnZlLCB0aW1lcz0gYygxMiwgMjQpKQpjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlLCBsZXZlbHM9YygiTkVHQVRJVkUiLCJQT1NJVElWRSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlLCBkYXRhPWNpcmNfZGF0YSkgCmdnZm9yZXN0KGNveF9maXQsZGF0YSA9IGNpcmNfZGF0YSkKc3VtbWFyeShjb3hfZml0KQpjb3hfZml0X3N1bW1hcnkgPC0gc3VtbWFyeShjb3hfZml0KQoKIyBFeHRyYWN0IHZhbHVlcyBmb3IgSFIsIDk1JSBDSSwgYW5kIHAtdmFsdWUKSFIgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1syXQpsb3dlcl9DSSA8LSBjb3hfZml0X3N1bW1hcnkkY29uZi5pbnRbM10KdXBwZXJfQ0kgPC0gY294X2ZpdF9zdW1tYXJ5JGNvbmYuaW50WzRdCnBfdmFsdWUgPC0gY294X2ZpdF9zdW1tYXJ5JGNvZWZmaWNpZW50c1s1XQpsYWJlbF90ZXh0IDwtIHBhc3RlMCgiSFIgPSAiLCByb3VuZChIUiwgMiksICIgKCIsIHJvdW5kKGxvd2VyX0NJLCAyKSwgIi0iLCByb3VuZCh1cHBlcl9DSSwgMiksICIpOyBwID0gIiwgcm91bmQocF92YWx1ZSwgMykpCnByaW50KGxhYmVsX3RleHQpCgojRmlzaGVyIHRlc3QgZm9yIERGUyBwZXJjZW50YWdlcyBhdCAxMiBhbmQgMjQgbW9udGhzCmRmc190aW1lcyA8LSBjKDEyLCAyNCkKY2lyY19kYXRhIDwtIG5hLm9taXQoY2lyY19kYXRhWywgYygiY3RETkEuU3VydmVpbGxhbmNlIiwgIkRGUy5tb250aHMiLCAiREZTLkV2ZW50IildKQpwX3ZhbHVlcyA8LSBzYXBwbHkoZGZzX3RpbWVzLCBmdW5jdGlvbih0aW1lKSB7CiAgbmVnX2NvdW50IDwtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJORUdBVElWRSIgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA+PSB0aW1lICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAwKQogIHBvc19jb3VudCA8LSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiUE9TSVRJVkUiICYgY2lyY19kYXRhJERGUy5tb250aHMgPj0gdGltZSAmIGNpcmNfZGF0YSRERlMuRXZlbnQgPT0gMCkKICBuZWdfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIk5FR0FUSVZFIikKICBwb3NfdG90YWwgPC0gc3VtKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPT0gIlBPU0lUSVZFIikKICAKICBuZWdfc3VydiA8LSBuZWdfdG90YWwgLSBzdW0oY2lyY19kYXRhJGN0RE5BLlN1cnZlaWxsYW5jZSA9PSAiTkVHQVRJVkUiICYgY2lyY19kYXRhJERGUy5FdmVudCA9PSAxICYgY2lyY19kYXRhJERGUy5tb250aHMgPCB0aW1lKQogIHBvc19zdXJ2IDwtIHBvc190b3RhbCAtIHN1bShjaXJjX2RhdGEkY3RETkEuU3VydmVpbGxhbmNlID09ICJQT1NJVElWRSIgJiBjaXJjX2RhdGEkREZTLkV2ZW50ID09IDEgJiBjaXJjX2RhdGEkREZTLm1vbnRocyA8IHRpbWUpCiAgCiAgc3Vydl9tYXRyaXggPC0gbWF0cml4KGMobmVnX3N1cnYsIHBvc19zdXJ2LCBuZWdfdG90YWwgLSBuZWdfc3VydiwgcG9zX3RvdGFsIC0gcG9zX3N1cnYpLCBucm93ID0gMikKICB0ZXN0X3Jlc3VsdCA8LSBmaXNoZXIudGVzdChzdXJ2X21hdHJpeCkKICByZXR1cm4odGVzdF9yZXN1bHQkcC52YWx1ZSkKfSkKbmFtZXMocF92YWx1ZXMpIDwtIHBhc3RlMCgicC12YWx1ZSBhdCAiLCBkZnNfdGltZXMsICIgbW9udGhzIikKcHJpbnQocF92YWx1ZXMpCmBgYAoKCgoKI011bHRpdmFyaWF0ZSBjb3ggcmVncmVzc2lvbiBhdCBTdXJ2ZWlsbGFuY2UgV2luZG93IGZvciBERlMgLSBBbGwgc3RhZ2VzIExhbmRtYXJrIDEwIHdlZWtzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UhPSIiLF0KY2lyY19kYXRhJERGUy5tb250aHM9Y2lyY19kYXRhJERGUy5tb250aHMtMi41CmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJERGUy5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UgPC0gZmFjdG9yKGNpcmNfZGF0YSRjdEROQS5TdXJ2ZWlsbGFuY2UsIGxldmVscz1jKCJORUdBVElWRSIsIlBPU0lUSVZFIiksIGxhYmVscyA9IGMoIk5lZ2F0aXZlIiwgIlBvc2l0aXZlIikpCmNpcmNfZGF0YSRHZW5kZXIgPC0gZmFjdG9yKGNpcmNfZGF0YSRHZW5kZXIsIGxldmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmNpcmNfZGF0YSRBZ2UuR3JvdXAgPC0gZmFjdG9yKGNpcmNfZGF0YSRBZ2UuR3JvdXAsIGxldmVscyA9IGMoIjEiLCAiMiIpLCBsYWJlbHMgPSBjKCI8NzAiLCAiPjcwIikpCmNpcmNfZGF0YSRQcmltU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFByaW1TaXRlLCBsZXZlbHMgPSBjKCJMZWZ0LXNpZGVkIGNvbG9uIiwgIlJpZ2h0LXNpZGVkIGNvbG9uIikpCmNpcmNfZGF0YSRFQ09HIDwtIGZhY3RvcihjaXJjX2RhdGEkRUNPRywgbGV2ZWxzID0gYygiMCIsICIxIikpCmNpcmNfZGF0YSRwVCA8LSBmYWN0b3IoY2lyY19kYXRhJHBULCBsZXZlbHMgPSBjKCJUMS1UMiIsICJUMy1UNCIpKQpjaXJjX2RhdGEkcE4gPC0gZmFjdG9yKGNpcmNfZGF0YSRwTiwgbGV2ZWxzID0gYygiTjAiLCAiTjEtTjIiKSkKY2lyY19kYXRhJExWSSA8LSBmYWN0b3IoY2lyY19kYXRhJExWSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSkKY2lyY19kYXRhJFBOSSA8LSBmYWN0b3IoY2lyY19kYXRhJFBOSSwgbGV2ZWxzID0gYygiVFJVRSIsICJGQUxTRSIpLCBsYWJlbHMgPSBjKCJZZXMiLCAiTm8iKSkKY2lyY19kYXRhJEdyYWRlIDwtIGZhY3RvcihjaXJjX2RhdGEkR3JhZGUsIGxldmVscyA9IGMoIkcxIiwgIkcyL0czIikpCmNpcmNfZGF0YSRSQVMgPC0gZmFjdG9yKGNpcmNfZGF0YSRSQVMsIGxldmVscyA9IGMoIldUIiwgIk1VVCIpLCBsYWJlbHMgPSBjKCJXaWxkLVR5cGUiLCAiTXV0YW50IikpCnN1cnZfb2JqZWN0IDwtIFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMubW9udGhzLCBldmVudCA9IGNpcmNfZGF0YSRERlMuRXZlbnQpIApjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuU3VydmVpbGxhbmNlICsgR2VuZGVyICsgQWdlLkdyb3VwICsgRUNPRyArIHBUICsgcE4gKyBMVkkgKyBQTkkgKyBHcmFkZSArIFJBUywgZGF0YT1jaXJjX2RhdGEpIApnZ2ZvcmVzdChjb3hfZml0LCBkYXRhID0gY2lyY19kYXRhLCBtYWluID0gIk11bHRpdmFyaWF0ZSBSZWdyZXNzaW9uIE1vZGVsIGZvciBERlMgLSBBbGwgU3RhZ2VzIiwgcmVmTGFiZWwgPSAiUmVmZXJlbmNlIEdyb3VwIikKdGVzdC5waCA8LSBjb3guenBoKGNveF9maXQpCmBgYAoKCiNERlMgYnkgY3RETkEgRHluYW1pY3MgZnJvbSBNUkQgdG8gNiBtb250aHMgLSBhbGwgc3RhZ2VzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRjdEROQS5NUkQhPSIiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkREZTLjZtby5tb250aHM+PTAsXQpjaXJjX2RhdGFkZiA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCmNpcmNfZGF0YSRjdEROQS5EeW5hbWljcyA8LSBOQSAjZmlyc3Qgd2UgY3JlYXRlIHRoZSB2YXJpYWJsZSBmb3IgdGhlIGN0RE5BICYgTkFDIGNvbWJpbmF0aW9uLCBhbmQgd2UgYXNzaWduIHZhbHVlcwpjaXJjX2RhdGEgPC0gY2lyY19kYXRhICU+JQogIG11dGF0ZShjdEROQS5EeW5hbWljcyA9IGNhc2Vfd2hlbigKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiIH4gMSwKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiTkVHQVRJVkUiIH4gMiwKICAgIGN0RE5BLk1SRCA9PSAiTkVHQVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiIH4gMywKICAgIGN0RE5BLk1SRCA9PSAiUE9TSVRJVkUiICYgY3RETkEuNm1vbnRocyA9PSAiUE9TSVRJVkUiIH4gNAogICkpCgpzdXJ2Zml0KFN1cnYodGltZSA9IGNpcmNfZGF0YSRERlMuNm1vLm1vbnRocywgZXZlbnQgPSBjaXJjX2RhdGEkREZTLkV2ZW50KX5jdEROQS5EeW5hbWljcywgZGF0YSA9IGNpcmNfZGF0YSkKZXZlbnRfc3VtbWFyeSA8LSBjaXJjX2RhdGEgJT4lCiAgZ3JvdXBfYnkoY3RETkEuRHluYW1pY3MpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsID0gbigpLAogICAgRXZlbnRzID0gc3VtKERGUy5FdmVudCksCiAgICBGcmFjdGlvbiA9IEV2ZW50cyAvIG4oKSwKICAgIFBlcmNlbnRhZ2UgPSAoRXZlbnRzIC8gbigpKSAqIDEwMAogICkKcHJpbnQoZXZlbnRfc3VtbWFyeSkKc3Vydl9vYmplY3QgPC1TdXJ2KHRpbWUgPSBjaXJjX2RhdGEkREZTLjZtby5tb250aHMsIGV2ZW50ID0gY2lyY19kYXRhJERGUy5FdmVudCkKS01fY3VydmUgPC0gc3VydmZpdChzdXJ2X29iamVjdCB+IGN0RE5BLkR5bmFtaWNzLCBkYXRhID0gY2lyY19kYXRhLGNvbmYuaW50PTAuOTUsY29uZi50eXBlPSJsb2ctbG9nIikgCmdnc3VydnBsb3QoS01fY3VydmUsIGRhdGEgPSBjaXJjX2RhdGEsIHB2YWwgPSBGQUxTRSwgY29uZi5pbnQgPSBGQUxTRSwgcmlzay50YWJsZSA9IFRSVUUsIGJyZWFrLnRpbWUuYnk9NiwgcGFsZXR0ZT1jKCJibHVlIiwiZ3JlZW4iLCJwdXJwbGUiLCAicmVkIiksIHRpdGxlPSJERlMgLSBjdEROQSBEeW5hbWljcyBmcm9tIE1SRCB0byA2IG1vbnRocyB8IEFsbCBTdGFnZXMiLCB5bGFiPSAiRGlzZWFzZS1GcmVlIFN1cnZpdmFsIiwgeGxhYj0iVGltZSBmcm9tIExhbmRtYXJrIFRpbWUgcG9pbnQgKE1vbnRocykiLCBsZWdlbmQubGFicz1jKCJQZXJzaXN0ZW50bHkgTmVnYXRpdmUiLCAiQ29udmVydGVkIE5lZ2F0aXZlIiwiQ29udmVydGVkIFBvc2l0aXZlIiwgIlBlcnNpc3RlbnRseSBQb3NpdGl2ZSIpLCBsZWdlbmQudGl0bGU9IiIpCnN1bW1hcnkoS01fY3VydmUsIHRpbWVzPSBjKDI0KSkKY2lyY19kYXRhJGN0RE5BLkR5bmFtaWNzIDwtIGZhY3RvcihjaXJjX2RhdGEkY3RETkEuRHluYW1pY3MsIGxldmVscz1jKCIxIiwiMiIsIjMiLCAiNCIpLCBsYWJlbHMgPSBjKCJQZXJzaXN0ZW50bHkgTmVnYXRpdmUiLCAiQ29udmVydGVkIE5lZ2F0aXZlIiwiQ29udmVydGVkIFBvc2l0aXZlIiwgIlBlcnNpc3RlbnRseSBQb3NpdGl2ZSIpKQpjb3hfZml0IDwtIGNveHBoKHN1cnZfb2JqZWN0IH4gY3RETkEuRHluYW1pY3MsIGRhdGE9Y2lyY19kYXRhKSAKZ2dmb3Jlc3QoY294X2ZpdCxkYXRhID0gY2lyY19kYXRhKSAKc3VtbWFyeShjb3hfZml0KQpgYGAKCgojVGFibGUgd2l0aCByZWN1cnJlbmNlIHNpdGVzIGJ5IGN0RE5BIGF0IHRoZSBNUkQgV2luZG93CmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQ9PSJUUlVFIixdCgpjaXJjX2RhdGFfc3Vic2V0MSA8LSBjaXJjX2RhdGEgJT4lCiAgc2VsZWN0KAogICAgUmVsLlNpdGUpICU+JQogIG11dGF0ZSgKICAgIFJlbC5TaXRlID0gZmFjdG9yKFJlbC5TaXRlLCBsZXZlbHMgPSBjKCJMb2NhbCIsICJMeW1waCBOb2RlIiwgIkxpdmVyIiwgIkx1bmciLCAiUGVyaXRvbmV1bSIsICJCcmFpbiIpKSkKCmNpcmNfZGF0YV9zdWJzZXQyIDwtIGNpcmNfZGF0YSAlPiUKICBzZWxlY3QoCiAgICBSZWwuU2l0ZSwKICAgIGN0RE5BLk1SRCkgJT4lCiAgbXV0YXRlKAogICAgUmVsLlNpdGUgPSBmYWN0b3IoUmVsLlNpdGUsIGxldmVscyA9IGMoIkxvY2FsIiwgIkx5bXBoIE5vZGUiLCAiTGl2ZXIiLCAiTHVuZyIsICJQZXJpdG9uZXVtIiwgIkJyYWluIikpLAogICAgY3RETkEuTVJEID0gZmFjdG9yKGN0RE5BLk1SRCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSkpCk92ZXJhbGwgPC0gY2lyY19kYXRhX3N1YnNldDEgJT4lCiAgdGJsX3N1bW1hcnkoCiAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICBhbGxfY29udGludW91cygpIH4gInttZWRpYW59ICh7bWlufSAtIHttYXh9KSIsCiAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAoe3B9JSkiKSkgJT4lCiAgYm9sZF9sYWJlbHMoKQpPdmVyYWxsCgpCeWN0RE5BX01SRCA8LSBjaXJjX2RhdGFfc3Vic2V0MiAlPiUKICB0Ymxfc3VtbWFyeSgKICAgIGJ5ID0gY3RETkEuTVJELCAjIGFkZCB0aGlzIGxpbmUgdG8gc3ViZ3JvdXAgYnkgY3RETkEuTVJECiAgICBzdGF0aXN0aWMgPSBsaXN0KAogICAgICBhbGxfY29udGludW91cygpIH4gInttZWRpYW59ICh7bWlufSAtIHttYXh9KSIsCiAgICAgIGFsbF9jYXRlZ29yaWNhbCgpIH4gIntufSAoe3B9JSkiKSkgJT4lCiAgYWRkX3AoKSAlPiUKICBib2xkX2xhYmVscygpCkJ5Y3RETkFfTVJECgptZXJnZWRfdGFibGUgPC0gdGJsX21lcmdlKHRibHM9bGlzdChPdmVyYWxsLCBCeWN0RE5BX01SRCkpCm1lcmdlZF90YWJsZQoKZml0MSA8LSBhc19mbGV4X3RhYmxlKAogIG1lcmdlZF90YWJsZSwKICBpbmNsdWRlID0gZXZlcnl0aGluZygpLAogIHJldHVybl9jYWxscyA9IEZBTFNFKQpmaXQxCnNhdmVfYXNfZG9jeChmaXQxLCBwYXRoPSAifi9Eb3dubG9hZHMvbWVyZ2VkX3RhYmxlLmRvY3giKQpgYGAKCgojTVRNL21MIGxldmVscyBhdCB0aGUgTVJEIFdpbmRvdyBieSBSYWRpb2xvZ2ljYWwgUmVjdXJyZW5jZQpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCiMgVHJhbnNmb3JtIHBfTVJEX01UTSB3aXRoIGxvZzEwCmNpcmNfZGF0YSRwX01SRF9NVE0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY2lyY19kYXRhJHBfTVJEX01UTSkpCmNpcmNfZGF0YSRSRlMuRXZlbnQgPC0gZmFjdG9yKGNpcmNfZGF0YSRSRlMuRXZlbnQsIGxldmVscyA9IGMoIkZBTFNFIiwgIlRSVUUiKSwgbGFiZWxzID0gYygiTm8gUmVjdXJyZW5jZSIsICJSZWN1cnJlbmNlIikpCnN1bW1hcnlfc3RhdHMgPC0gY2lyY19kYXRhICU+JQogIGdyb3VwX2J5KFJGUy5FdmVudCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbWVkaWFuX3BfTVJEX01UTSA9IG1lZGlhbihwX01SRF9NVE0sIG5hLnJtID0gVFJVRSksCiAgICByYW5nZV9wX01SRF9NVE0gPSBwYXN0ZTAobWluKHBfTVJEX01UTSwgbmEucm0gPSBUUlVFKSwgIiAtICIsIG1heChwX01SRF9NVE0sIG5hLnJtID0gVFJVRSkpCiAgKQpwcmludChzdW1tYXJ5X3N0YXRzKQoKbTNfMXYyIDwtIHdpbGNveC50ZXN0KHBfTVJEX01UTSB+IFJGUy5FdmVudCwKICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjaXJjX2RhdGFbY2lyY19kYXRhJFJGUy5FdmVudCAlaW4lIGMoIk5vIFJlY3VycmVuY2UiLCAiUmVjdXJyZW5jZSIpLCBdLAogICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKQpwcmludChtM18xdjIpCmJveHBsb3QocF9NUkRfTVRNflJGUy5FdmVudCwgZGF0YT1jaXJjX2RhdGEsIG1haW49ImN0RE5BIE1SRCBXaW5kb3cgTVRNIC0gUmVjdXJyZW5jZSIsIHhsYWI9IlJlY3VycmVuY2UiLCB5bGFiPSJNVE0vbUwiLCBjb2w9IndoaXRlIixib3JkZXI9ImJsYWNrIiwgeWxpbSA9IGMoMCwgNTApKQpgYGAKCiNNVE0vbUwgbGV2ZWxzIGF0IHRoZSBNUkQgV2luZG93IGJ5IFJhZGlvbG9naWNhbCBSZWN1cnJlbmNlIFNpdGVzCmBgYHtyfQpybShsaXN0PWxzKCkpCnNldHdkKCJ+L0Rvd25sb2FkcyIpCmNpcmNfZGF0YSA8LSByZWFkLmNzdigiR2FsYXh5IERhdGFfMjAyNDA2MDMgQ29tcGxldGUgRGF0YXNldC5jc3YiKQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRDb2hvcnRCPT0iVFJVRSIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRSRlMuRXZlbnQ9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRCE9IiIsXQpjaXJjX2RhdGEgPC0gY2lyY19kYXRhW2NpcmNfZGF0YSRERlMuTVJELm1vbnRocz49MCxdCmNpcmNfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKGNpcmNfZGF0YSkKCiMgVHJhbnNmb3JtIHBfTVJEX01UTSB3aXRoIGxvZzEwCmNpcmNfZGF0YSRwX01SRF9NVE0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY2lyY19kYXRhJHBfTVJEX01UTSkpCmNpcmNfZGF0YSRSZWwuU2l0ZSA8LSBmYWN0b3IoY2lyY19kYXRhJFJlbC5TaXRlLCBsZXZlbHMgPSBjKCJMaXZlciIsICJMeW1waCBOb2RlIiwgIkxvY2FsIiwgIlBlcml0b25ldW0iLCAiTHVuZyIsICJCcmFpbiIpKQpzdW1tYXJ5X3N0YXRzIDwtIGNpcmNfZGF0YSAlPiUKICBncm91cF9ieShSZWwuU2l0ZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbWVkaWFuX3BfTVJEX01UTSA9IG1lZGlhbihwX01SRF9NVE0sIG5hLnJtID0gVFJVRSksCiAgICByYW5nZV9wX01SRF9NVE0gPSBwYXN0ZTAobWluKHBfTVJEX01UTSwgbmEucm0gPSBUUlVFKSwgIiAtICIsIG1heChwX01SRF9NVE0sIG5hLnJtID0gVFJVRSkpCiAgKQpwcmludChzdW1tYXJ5X3N0YXRzKQprcnVza2FsX3Rlc3QgPC0ga3J1c2thbC50ZXN0KHBfTVJEX01UTSB+IFJlbC5TaXRlLCBkYXRhID0gY2lyY19kYXRhKQpwcmludChrcnVza2FsX3Rlc3QpCmJveHBsb3QocF9NUkRfTVRNflJlbC5TaXRlLCBkYXRhPWNpcmNfZGF0YSwgbWFpbj0iY3RETkEgTVJEIFdpbmRvdyBNVE0gLSBSZWN1cnJlbmNlIFNpdGUiLCB4bGFiPSJSZWN1cnJlbmNlIFNpdGUiLCB5bGFiPSJNVE0vbUwiLCBjb2w9IndoaXRlIixib3JkZXI9ImJsYWNrIiwgeWxpbSA9IGMoMCwgNDApKQpgYGAKCiNCYXJwbG90IHdpdGggUmVjdXJyZW5jZSBTaXRlcyAoTGl2ZXIgdnMgT3RoZXJzKSBieSBjdEROQSBhdCB0aGUgTVJEIFdpbmRvdwpgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgifi9Eb3dubG9hZHMiKQpjaXJjX2RhdGEgPC0gcmVhZC5jc3YoIkdhbGF4eSBEYXRhXzIwMjQwNjAzIENvbXBsZXRlIERhdGFzZXQuY3N2IikKY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkQ29ob3J0Qj09IlRSVUUiLF0KY2lyY19kYXRhIDwtIGNpcmNfZGF0YVtjaXJjX2RhdGEkUkZTLkV2ZW50PT0iVFJVRSIsXQoKY2lyY19kYXRhJGN0RE5BLk1SRCA8LSBmYWN0b3IoY2lyY19kYXRhJGN0RE5BLk1SRCwgbGV2ZWxzID0gYygiTkVHQVRJVkUiLCAiUE9TSVRJVkUiKSwgbGFiZWxzID0gYygiTmVnYXRpdmUiLCAiUG9zaXRpdmUiKSkKY2lyY19kYXRhJFJlbC5TaXRlIDwtIGZhY3RvcihjaXJjX2RhdGEkUmVsLlNpdGUsIGxldmVscyA9IGMoIkxpdmVyIiwgIkx5bXBoIE5vZGUiLCAiTG9jYWwiLCAiUGVyaXRvbmV1bSIsICJMdW5nIiwgIkJyYWluIikpCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGNpcmNfZGF0YSRSZWwuU2l0ZSwgY2lyY19kYXRhJGN0RE5BLk1SRCkKY2hpX3NxdWFyZV90ZXN0IDwtIGNoaXNxLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGNoaV9zcXVhcmVfdGVzdCkKZmlzaGVyX2V4YWN0X3Rlc3QgPC0gZmlzaGVyLnRlc3QoY29udGluZ2VuY3lfdGFibGUpCnByaW50KGZpc2hlcl9leGFjdF90ZXN0KQpwcmludChjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYgPC0gYXMuZGF0YS5mcmFtZShjb250aW5nZW5jeV90YWJsZSkKdGFibGVfZGYkVG90YWwgPC0gYXZlKHRhYmxlX2RmJEZyZXEsIHRhYmxlX2RmJFZhcjEsIEZVTiA9IHN1bSkKdGFibGVfZGYkUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRGcmVxIC8gdGFibGVfZGYkVG90YWwKdGFibGVfZGYkTWlkZGxlUGVyY2VudGFnZSA8LSB0YWJsZV9kZiRQZXJjZW50YWdlIC8gMgpnZ3Bsb3QodGFibGVfZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFBlcmNlbnRhZ2UsIGZpbGwgPSBWYXIyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyh5ID0gTWlkZGxlUGVyY2VudGFnZSwgbGFiZWwgPSBGcmVxKSwgcG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIsIHZqdXN0ID0gMS41LCBzaXplID0gNykgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJQYXRpZW50cyB3aXRoIFJhZGlvbG9naWNhbCBSZWN1cnJlbmNlIiwgCiAgICAgICB4ID0gIlJlY3VycmVuY2UgU2l0ZSIsIAogICAgICAgeSA9ICJQYXRpZW50cyAoJSkiLCAKICAgICAgIGZpbGwgPSAiY3RETkEgYXQgTVJEIiwKICAgICAgIGNhcHRpb24gPSBwYXN0ZSgiQ2hpLXNxdWFyZWQgdGVzdCBwLXZhbHVlOiAiLCBmb3JtYXQucHZhbChjaGlfc3F1YXJlX3Rlc3QkcC52YWx1ZSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5lZ2F0aXZlIiA9ICJibHVlIiwgIlBvc2l0aXZlIiA9ICJyZWQiKSkgKyAjIGRlZmluZSBjdXN0b20gY29sb3JzCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEuNSwgc2l6ZSA9IDE0KSwgIyBpbmNyZWFzZSB4LWF4aXMgdGV4dCBzaXplCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHktYXhpcyB0ZXh0IHNpemUKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLCAjIGluY3JlYXNlIHgtYXhpcyBsYWJlbCBzaXplCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgY29sb3IgPSAiYmxhY2siKSwgIyBpbmNyZWFzZSB5LWF4aXMgbGFiZWwgc2l6ZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSkgICMgaW5jcmVhc2UgUmVjdXJyZW5jZSBsYWJlbCBzaXplCmBgYAoKI0RldGVjdGlvbiBjdEROQSByYXRlcyBiYXNlZCBvbiBzaXRlcyBvZiByZWxhcHNlCmBgYHtyfQojIFJlbW92ZSBleGlzdGluZyBvYmplY3RzIGFuZCBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5CnJtKGxpc3Q9bHMoKSkKc2V0d2QoIn4vRG93bmxvYWRzIikKY2lyY19kYXRhIDwtIHJlYWQuY3N2KCJHYWxheHkgRGF0YV8yMDI0MDYwMyBDb21wbGV0ZSBEYXRhc2V0LmNzdiIpCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJENvaG9ydEI9PSJUUlVFIixdCmNpcmNfZGF0YSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJFJGUy5FdmVudD09IlRSVUUiLF0KCiMgQ3JlYXRlIGEgdGFibGUgb2YgY291bnRzIGZvciB0aGUgIlJlbC5TaXRlIiB2YXJpYWJsZQpyZWxzaXRlX2NvdW50cyA8LSB0YWJsZShjaXJjX2RhdGEkUmVsLlNpdGUpCnJlbHNpdGVfZGYgPC0gYXMuZGF0YS5mcmFtZShyZWxzaXRlX2NvdW50cykKbmFtZXMocmVsc2l0ZV9kZikgPC0gYygiUmVsLlNpdGUiLCAiQ291bnQiKQpjaXJjX2RhdGFfcG9zX21yZCA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLk1SRD09IlBPU0lUSVZFIixdCmNpcmNfZGF0YV9wb3NfYW55dGltZSA8LSBjaXJjX2RhdGFbY2lyY19kYXRhJGN0RE5BLmFueXRpbWU9PSJQT1NJVElWRSIsXQpwb3NfY291bnRzX21yZCA8LSB0YWJsZShjaXJjX2RhdGFfcG9zX21yZCRSZWwuU2l0ZSkKcG9zX2NvdW50c19hbnl0aW1lIDwtIHRhYmxlKGNpcmNfZGF0YV9wb3NfYW55dGltZSRSZWwuU2l0ZSkKcmVsc2l0ZV9kZiRNUkRQb3NfQ291bnQgPC0gaWZlbHNlKGlzLm5hKG1hdGNoKHJlbHNpdGVfZGYkUmVsLlNpdGUsIG5hbWVzKHBvc19jb3VudHNfbXJkKSkpLCAwLCBwb3NfY291bnRzX21yZFttYXRjaChyZWxzaXRlX2RmJFJlbC5TaXRlLCBuYW1lcyhwb3NfY291bnRzX21yZCkpXSkKcmVsc2l0ZV9kZiRNUkRQb3NfQ291bnRbaXMubmEocmVsc2l0ZV9kZiRNUkRQb3NfQ291bnQpXSA8LSAwCnJlbHNpdGVfZGYkQW55dGltZVBvc19Db3VudCA8LSBpZmVsc2UoaXMubmEobWF0Y2gocmVsc2l0ZV9kZiRSZWwuU2l0ZSwgbmFtZXMocG9zX2NvdW50c19hbnl0aW1lKSkpLCAwLCBwb3NfY291bnRzX2FueXRpbWVbbWF0Y2gocmVsc2l0ZV9kZiRSZWwuU2l0ZSwgbmFtZXMocG9zX2NvdW50c19hbnl0aW1lKSldKQpyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnRbaXMubmEocmVsc2l0ZV9kZiRBbnl0aW1lUG9zX0NvdW50KV0gPC0gMApyZWxzaXRlX2RmJFBlcmNlbnQgPC0gKHJlbHNpdGVfZGYkQ291bnQgLyBzdW0ocmVsc2l0ZV9kZiRDb3VudCkpICogMTAwCnJlbHNpdGVfZGYkTVJEUG9zX1BlcmNlbnQgPC0gKHJlbHNpdGVfZGYkTVJEUG9zX0NvdW50IC8gcmVsc2l0ZV9kZiRDb3VudCkgKiAxMDAKcmVsc2l0ZV9kZiRBbnl0aW1lUG9zX1BlcmNlbnQgPC0gKHJlbHNpdGVfZGYkQW55dGltZVBvc19Db3VudCAvIHJlbHNpdGVfZGYkQ291bnQpICogMTAwCnRvdGFsX29ic2VydmF0aW9ucyA8LSBzdW0ocmVsc2l0ZV9kZiRDb3VudCkKdG90YWxfcG9zX21yZCA8LSBzdW0ocmVsc2l0ZV9kZiRNUkRQb3NfQ291bnQpCnRvdGFsX3Bvc19hbnl0aW1lIDwtIHN1bShyZWxzaXRlX2RmJEFueXRpbWVQb3NfQ291bnQpCnRvdGFsX3JvdyA8LSBkYXRhLmZyYW1lKFJlbC5TaXRlID0gIlRvdGFsIiwgQ291bnQgPSB0b3RhbF9vYnNlcnZhdGlvbnMsIE1SRFBvc19Db3VudCA9IHRvdGFsX3Bvc19tcmQsIEFueXRpbWVQb3NfQ291bnQgPSB0b3RhbF9wb3NfYW55dGltZSwgUGVyY2VudCA9IDEwMCwgTVJEUG9zX1BlcmNlbnQgPSAodG90YWxfcG9zX21yZCAvIHRvdGFsX29ic2VydmF0aW9ucykgKiAxMDAsIEFueXRpbWVQb3NfUGVyY2VudCA9ICh0b3RhbF9wb3NfYW55dGltZSAvIHRvdGFsX29ic2VydmF0aW9ucykgKiAxMDApCnJlbHNpdGVfZGYgPC0gcmJpbmQocmVsc2l0ZV9kZiwgdG90YWxfcm93KQpwcmludChyZWxzaXRlX2RmKQoKZnQgPC0gZmxleHRhYmxlKHJlbHNpdGVfZGYpCmRvYyA8LSByZWFkX2RvY3goKSAlPiUKICBib2R5X2FkZF9mbGV4dGFibGUodmFsdWUgPSBmdCkKcHJpbnQoZG9jLCB0YXJnZXQgPSAicmVsc2l0ZV9kZi5kb2N4IikKYGBgCgo=